distrib/ext4_utils: new third-party library sources.

This patch adds the sources for the ext4_utils library that
will be used to create empty ext4 partition images on demand.

This is necessary to get rid of the YAFFS2 cache partition images
that are no longer supported by the next version of the Android
kernel (3.10).

Change-Id: Ia12bbb4d9cb31600c25ea6f66446ed98a7e85b1f
diff --git a/Makefile.android b/Makefile.android
index 9ac5c73..f4caf40 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -395,6 +395,7 @@
 # Build libsparse and related executables.
 include $(LOCAL_PATH)/distrib/libsparse/sources.mk
 include $(LOCAL_PATH)/distrib/libselinux/sources.mk
+include $(LOCAL_PATH)/distrib/ext4_utils/sources.mk
 
 ##############################################################################
 ##############################################################################
diff --git a/distrib/ext4_utils/README b/distrib/ext4_utils/README
new file mode 100644
index 0000000..d1defee
--- /dev/null
+++ b/distrib/ext4_utils/README
@@ -0,0 +1,4 @@
+This directory contains a copy of the $AOSP/system/extras/ext4_utils
+library at the following commit:
+
+    9c82554ee3284b57df9d8dfdf11467066ab0877a
diff --git a/distrib/ext4_utils/include/make_ext4fs.h b/distrib/ext4_utils/include/make_ext4fs.h
new file mode 100644
index 0000000..a3767e3
--- /dev/null
+++ b/distrib/ext4_utils/include/make_ext4fs.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _MAKE_EXT4FS_H_
+#define _MAKE_EXT4FS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct selabel_handle;
+
+int make_ext4fs(const char *filename, long long len,
+                const char *mountpoint, struct selabel_handle *sehnd);
+
+int make_ext4fs_extra(const char *filename, long long len,
+                      const char *mountpoint, struct selabel_handle *sehnd,
+                      int wipe, int verbose);
+
+int make_ext4fs_sparse_fd(int fd, long long len,
+                const char *mountpoint, struct selabel_handle *sehnd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/distrib/ext4_utils/include/private/android_filesystem_capability.h b/distrib/ext4_utils/include/private/android_filesystem_capability.h
new file mode 100644
index 0000000..0505cda
--- /dev/null
+++ b/distrib/ext4_utils/include/private/android_filesystem_capability.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Taken from linux/capability.h, with minor modifications
+ */
+
+#ifndef _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+#define _SYSTEM_CORE_INCLUDE_PRIVATE_ANDROID_FILESYSTEM_CAPABILITY_H
+
+#include <stdint.h>
+
+#define __user
+#define __u32 uint32_t
+#define __le32 uint32_t
+
+#define _LINUX_CAPABILITY_VERSION_1 0x19980330
+#define _LINUX_CAPABILITY_U32S_1 1
+#define _LINUX_CAPABILITY_VERSION_2 0x20071026
+#define _LINUX_CAPABILITY_U32S_2 2
+#define _LINUX_CAPABILITY_VERSION_3 0x20080522
+#define _LINUX_CAPABILITY_U32S_3 2
+
+typedef struct __user_cap_header_struct {
+ __u32 version;
+ int pid;
+} __user *cap_user_header_t;
+
+typedef struct __user_cap_data_struct {
+ __u32 effective;
+ __u32 permitted;
+ __u32 inheritable;
+} __user *cap_user_data_t;
+
+#define VFS_CAP_REVISION_MASK 0xFF000000
+#define VFS_CAP_REVISION_SHIFT 24
+#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK
+#define VFS_CAP_FLAGS_EFFECTIVE 0x000001
+#define VFS_CAP_REVISION_1 0x01000000
+#define VFS_CAP_U32_1 1
+#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1))
+#define VFS_CAP_REVISION_2 0x02000000
+#define VFS_CAP_U32_2 2
+#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))
+#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2
+#define VFS_CAP_U32 VFS_CAP_U32_2
+#define VFS_CAP_REVISION VFS_CAP_REVISION_2
+
+struct vfs_cap_data {
+ __le32 magic_etc;
+ struct {
+ __le32 permitted;
+ __le32 inheritable;
+ } data[VFS_CAP_U32];
+};
+
+#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1
+#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1
+#define CAP_CHOWN 0
+#define CAP_DAC_OVERRIDE 1
+#define CAP_DAC_READ_SEARCH 2
+#define CAP_FOWNER 3
+#define CAP_FSETID 4
+#define CAP_KILL 5
+#define CAP_SETGID 6
+#define CAP_SETUID 7
+#define CAP_SETPCAP 8
+#define CAP_LINUX_IMMUTABLE 9
+#define CAP_NET_BIND_SERVICE 10
+#define CAP_NET_BROADCAST 11
+#define CAP_NET_ADMIN 12
+#define CAP_NET_RAW 13
+#define CAP_IPC_LOCK 14
+#define CAP_IPC_OWNER 15
+#define CAP_SYS_MODULE 16
+#define CAP_SYS_RAWIO 17
+#define CAP_SYS_CHROOT 18
+#define CAP_SYS_PTRACE 19
+#define CAP_SYS_PACCT 20
+#define CAP_SYS_ADMIN 21
+#define CAP_SYS_BOOT 22
+#define CAP_SYS_NICE 23
+#define CAP_SYS_RESOURCE 24
+#define CAP_SYS_TIME 25
+#define CAP_SYS_TTY_CONFIG 26
+#define CAP_MKNOD 27
+#define CAP_LEASE 28
+#define CAP_AUDIT_WRITE 29
+#define CAP_AUDIT_CONTROL 30
+#define CAP_SETFCAP 31
+#define CAP_MAC_OVERRIDE 32
+#define CAP_MAC_ADMIN 33
+#define CAP_SYSLOG 34
+#define CAP_WAKE_ALARM 35
+#define CAP_LAST_CAP CAP_WAKE_ALARM
+#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP)
+#define CAP_TO_INDEX(x) ((x) >> 5)
+#define CAP_TO_MASK(x) (1 << ((x) & 31))
+
+#undef __user
+#undef __u32
+#undef __le32
+
+#endif
diff --git a/distrib/ext4_utils/sources.mk b/distrib/ext4_utils/sources.mk
new file mode 100644
index 0000000..172d54f
--- /dev/null
+++ b/distrib/ext4_utils/sources.mk
@@ -0,0 +1,68 @@
+OLD_LOCAL_PATH := $(LOCAL_PATH)
+LOCAL_PATH := $(call my-dir)
+
+LIBEXT4_UTILS_SOURCES := \
+    src/allocate.c \
+    src/contents.c \
+    src/crc16.c \
+    src/ext4_sb.c \
+    src/ext4_utils.c \
+    src/extent.c \
+    src/indirect.c \
+    src/make_ext4fs.c \
+    src/sha1.c \
+    src/uuid.c \
+    src/wipe.c \
+
+LIBEXT4_UTILS_INCLUDES := $(LOCAL_PATH)/include
+
+LIBEXT4_UTILS_CFLAGS := -DHOST
+ifeq ($(HOST_OS),windows)
+    LIBEXT4_UTILS_CFLAGS += -DUSE_MINGW=1
+endif
+
+$(call start-emulator-library,emulator-libext4_utils)
+LOCAL_SRC_FILES := $(LIBEXT4_UTILS_SOURCES)
+LOCAL_C_INCLUDES := \
+    $(LIBEXT4_UTILS_INCLUDES) \
+    $(LIBSPARSE_INCLUDES) \
+    $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBEXT4_UTILS_CFLAGS)
+$(call end-emulator-library)
+
+$(call start-emulator64-library,emulator64-libext4_utils)
+LOCAL_SRC_FILES := $(LIBEXT4_UTILS_SOURCES)
+LOCAL_C_INCLUDES := \
+    $(LIBEXT4_UTILS_INCLUDES) \
+    $(LIBSPARSE_INCLUDES) \
+    $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBEXT4_UTILS_CFLAGS)
+$(call end-emulator-library)
+
+$(call start-emulator-program,emulator_make_ext4fs)
+LOCAL_SRC_FILES := src/make_ext4fs_main.c
+LOCAL_C_INCLUDES := \
+    $(LIBEXT4_UTILS_INCLUDES) \
+    $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBEXT4_UTILS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := \
+    emulator-libext4_utils \
+    emulator-libsparse \
+    emulator-libselinux \
+    emulator-zlib
+$(call end-emulator-program)
+
+$(call start-emulator64-program,emulator64_make_ext4fs)
+LOCAL_SRC_FILES := src/make_ext4fs_main.c
+LOCAL_C_INCLUDES := \
+    $(LIBEXT4_UTILS_INCLUDES) \
+    $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBEXT4_UTILS_CFLAGS)
+LOCAL_STATIC_LIBRARIES := \
+    emulator64-libext4_utils \
+    emulator64-libsparse \
+    emulator64-libselinux \
+    emulator64-zlib
+$(call end-emulator-program)
+
+LOCAL_PATH := $(OLD_LOCAL_PATH)
\ No newline at end of file
diff --git a/distrib/ext4_utils/src/Android.mk b/distrib/ext4_utils/src/Android.mk
new file mode 100644
index 0000000..8cb04eb
--- /dev/null
+++ b/distrib/ext4_utils/src/Android.mk
@@ -0,0 +1,146 @@
+# Copyright 2010 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+
+libext4_utils_src_files := \
+    make_ext4fs.c \
+    ext4fixup.c \
+    ext4_utils.c \
+    allocate.c \
+    contents.c \
+    extent.c \
+    indirect.c \
+    uuid.c \
+    sha1.c \
+    wipe.c \
+    crc16.c \
+    ext4_sb.c
+
+#
+# -- All host/targets including windows
+#
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libext4_utils_src_files)
+LOCAL_MODULE := libext4_utils_host
+LOCAL_STATIC_LIBRARIES := \
+    libsparse_host \
+    libz
+ifneq ($(HOST_OS),windows)
+  LOCAL_STATIC_LIBRARIES += libselinux
+endif
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := make_ext4fs_main.c
+LOCAL_MODULE := make_ext4fs
+LOCAL_STATIC_LIBRARIES += \
+    libext4_utils_host \
+    libsparse_host \
+    libz
+ifeq ($(HOST_OS),windows)
+  LOCAL_LDLIBS += -lws2_32
+else
+  LOCAL_STATIC_LIBRARIES += libselinux
+  LOCAL_CFLAGS := -DHOST
+endif
+include $(BUILD_HOST_EXECUTABLE)
+
+
+#
+# -- All host/targets excluding windows
+#
+
+ifneq ($(HOST_OS),windows)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libext4_utils_src_files)
+LOCAL_MODULE := libext4_utils
+LOCAL_SHARED_LIBRARIES := \
+    libselinux \
+    libsparse \
+    libz
+include $(BUILD_SHARED_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(libext4_utils_src_files)
+LOCAL_MODULE := libext4_utils_static
+LOCAL_STATIC_LIBRARIES += \
+    libselinux \
+    libsparse_static
+include $(BUILD_STATIC_LIBRARY)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := make_ext4fs_main.c
+LOCAL_MODULE := make_ext4fs
+LOCAL_SHARED_LIBRARIES := \
+    libext4_utils \
+    libselinux \
+    libz
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ext2simg.c
+LOCAL_MODULE := ext2simg
+LOCAL_SHARED_LIBRARIES += \
+    libext4_utils \
+    libselinux \
+    libsparse \
+    libz
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ext2simg.c
+LOCAL_MODULE := ext2simg
+LOCAL_STATIC_LIBRARIES += \
+    libext4_utils_host \
+    libselinux \
+    libsparse_host \
+    libz
+include $(BUILD_HOST_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := setup_fs.c
+LOCAL_MODULE := setup_fs
+LOCAL_SHARED_LIBRARIES += libcutils
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ext4fixup_main.c
+LOCAL_MODULE := ext4fixup
+LOCAL_SHARED_LIBRARIES += \
+    libext4_utils \
+    libsparse \
+    libz
+include $(BUILD_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := ext4fixup_main.c
+LOCAL_MODULE := ext4fixup
+LOCAL_STATIC_LIBRARIES += \
+    libext4_utils_host \
+    libsparse_host \
+    libz
+include $(BUILD_HOST_EXECUTABLE)
+
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := mkuserimg.sh
+LOCAL_SRC_FILES := mkuserimg.sh
+LOCAL_MODULE_CLASS := EXECUTABLES
+# We don't need any additional suffix.
+LOCAL_MODULE_SUFFIX :=
+LOCAL_BUILT_MODULE_STEM := $(notdir $(LOCAL_SRC_FILES))
+LOCAL_IS_HOST_MODULE := true
+include $(BUILD_PREBUILT)
+
+endif
+
diff --git a/distrib/ext4_utils/src/MODULE_LICENSE_APACHE2 b/distrib/ext4_utils/src/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/distrib/ext4_utils/src/MODULE_LICENSE_APACHE2
diff --git a/distrib/ext4_utils/src/NOTICE b/distrib/ext4_utils/src/NOTICE
new file mode 100644
index 0000000..5d14293
--- /dev/null
+++ b/distrib/ext4_utils/src/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2010, 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.
+
+   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.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/distrib/ext4_utils/src/allocate.c b/distrib/ext4_utils/src/allocate.c
new file mode 100644
index 0000000..6397270
--- /dev/null
+++ b/distrib/ext4_utils/src/allocate.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2010 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 "ext4_utils.h"
+#include "allocate.h"
+
+#include <sparse/sparse.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+struct region_list {
+	struct region *first;
+	struct region *last;
+	struct region *iter;
+	u32 partial_iter;
+};
+
+struct block_allocation {
+	struct region_list list;
+	struct region_list oob_list;
+};
+
+struct region {
+	u32 block;
+	u32 len;
+	int bg;
+	struct region *next;
+	struct region *prev;
+};
+
+struct block_group_info {
+	u32 first_block;
+	int header_blocks;
+	int data_blocks_used;
+	int has_superblock;
+	u8 *bitmaps;
+	u8 *block_bitmap;
+	u8 *inode_bitmap;
+	u8 *inode_table;
+	u32 free_blocks;
+	u32 first_free_block;
+	u32 free_inodes;
+	u32 first_free_inode;
+	u16 flags;
+	u16 used_dirs;
+};
+
+struct xattr_list_element {
+	struct ext4_inode *inode;
+	struct ext4_xattr_header *header;
+	struct xattr_list_element *next;
+};
+
+struct block_allocation *create_allocation()
+{
+	struct block_allocation *alloc = malloc(sizeof(struct block_allocation));
+	alloc->list.first = NULL;
+	alloc->list.last = NULL;
+	alloc->oob_list.first = NULL;
+	alloc->oob_list.last = NULL;
+	alloc->list.iter = NULL;
+	alloc->list.partial_iter = 0;
+	alloc->oob_list.iter = NULL;
+	alloc->oob_list.partial_iter = 0;
+	return alloc;
+}
+
+static struct ext4_xattr_header *xattr_list_find(struct ext4_inode *inode)
+{
+	struct xattr_list_element *element;
+	for (element = aux_info.xattrs; element != NULL; element = element->next) {
+		if (element->inode == inode)
+			return element->header;
+	}
+	return NULL;
+}
+
+static void xattr_list_insert(struct ext4_inode *inode, struct ext4_xattr_header *header)
+{
+	struct xattr_list_element *element = malloc(sizeof(struct xattr_list_element));
+	element->inode = inode;
+	element->header = header;
+	element->next = aux_info.xattrs;
+	aux_info.xattrs = element;
+}
+
+static void region_list_remove(struct region_list *list, struct region *reg)
+{
+	if (reg->prev)
+		reg->prev->next = reg->next;
+
+	if (reg->next)
+		reg->next->prev = reg->prev;
+
+	if (list->first == reg)
+		list->first = reg->next;
+
+	if (list->last == reg)
+		list->last = reg->prev;
+
+	reg->next = NULL;
+	reg->prev = NULL;
+}
+
+static void region_list_append(struct region_list *list, struct region *reg)
+{
+	if (list->first == NULL) {
+		list->first = reg;
+		list->last = reg;
+		list->iter = reg;
+		list->partial_iter = 0;
+		reg->prev = NULL;
+	} else {
+		list->last->next = reg;
+		reg->prev = list->last;
+		list->last = reg;
+	}
+	reg->next = NULL;
+}
+
+#if 0
+static void dump_starting_from(struct region *reg)
+{
+	for (; reg; reg = reg->next) {
+		printf("%p: Blocks %d-%d (%d)\n", reg,
+				reg->bg * info.blocks_per_group + reg->block,
+				reg->bg * info.blocks_per_group + reg->block + reg->len - 1,
+				reg->len);
+	}
+}
+
+static void dump_region_lists(struct block_allocation *alloc) {
+
+	printf("Main list:\n");
+	dump_starting_from(alloc->list.first);
+
+	printf("OOB list:\n");
+	dump_starting_from(alloc->oob_list.first);
+}
+#endif
+
+void append_region(struct block_allocation *alloc,
+		u32 block, u32 len, int bg_num)
+{
+	struct region *reg;
+	reg = malloc(sizeof(struct region));
+	reg->block = block;
+	reg->len = len;
+	reg->bg = bg_num;
+	reg->next = NULL;
+
+	region_list_append(&alloc->list, reg);
+}
+
+static void allocate_bg_inode_table(struct block_group_info *bg)
+{
+	if (bg->inode_table != NULL)
+		return;
+
+	u32 block = bg->first_block + 2;
+
+	if (bg->has_superblock)
+		block += aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks + 1;
+
+	bg->inode_table = calloc(aux_info.inode_table_blocks, info.block_size);
+	if (bg->inode_table == NULL)
+		critical_error_errno("calloc");
+
+	sparse_file_add_data(ext4_sparse_file, bg->inode_table,
+			aux_info.inode_table_blocks	* info.block_size, block);
+
+	bg->flags &= ~EXT4_BG_INODE_UNINIT;
+}
+
+static int bitmap_set_bit(u8 *bitmap, u32 bit)
+{
+	if (bitmap[bit / 8] & 1 << (bit % 8))
+		return 1;
+
+	bitmap[bit / 8] |= 1 << (bit % 8);
+	return 0;
+}
+
+static int bitmap_set_8_bits(u8 *bitmap, u32 bit)
+{
+	int ret = bitmap[bit / 8];
+	bitmap[bit / 8] = 0xFF;
+	return ret;
+}
+
+/* Marks a the first num_blocks blocks in a block group as used, and accounts
+ for them in the block group free block info. */
+static int reserve_blocks(struct block_group_info *bg, u32 start, u32 num)
+{
+	unsigned int i = 0;
+
+	u32 block = start;
+	if (num > bg->free_blocks)
+		return -1;
+
+	for (i = 0; i < num && block % 8 != 0; i++, block++) {
+		if (bitmap_set_bit(bg->block_bitmap, block)) {
+			error("attempted to reserve already reserved block");
+			return -1;
+		}
+	}
+
+	for (; i + 8 <= (num & ~7); i += 8, block += 8) {
+		if (bitmap_set_8_bits(bg->block_bitmap, block)) {
+			error("attempted to reserve already reserved block");
+			return -1;
+		}
+	}
+
+	for (; i < num; i++, block++) {
+		if (bitmap_set_bit(bg->block_bitmap, block)) {
+			error("attempted to reserve already reserved block");
+			return -1;
+		}
+	}
+
+	bg->free_blocks -= num;
+	if (start == bg->first_free_block)
+		bg->first_free_block = start + num;
+
+	return 0;
+}
+
+static void free_blocks(struct block_group_info *bg, u32 num_blocks)
+{
+	unsigned int i;
+	u32 block = bg->first_free_block - 1;
+	for (i = 0; i < num_blocks; i++, block--)
+		bg->block_bitmap[block / 8] &= ~(1 << (block % 8));
+	bg->free_blocks += num_blocks;
+	bg->first_free_block -= num_blocks;
+}
+
+/* Reduces an existing allocation by len blocks by return the last blocks
+   to the free pool in their block group. Assumes that the blocks being
+   returned were the last ones allocated out of the block group */
+void reduce_allocation(struct block_allocation *alloc, u32 len)
+{
+	while (len) {
+		struct region *last_reg = alloc->list.last;
+
+		if (last_reg->len > len) {
+			free_blocks(&aux_info.bgs[last_reg->bg], len);
+			last_reg->len -= len;
+			len = 0;
+		} else {
+			struct region *reg = alloc->list.last->prev;
+			free_blocks(&aux_info.bgs[last_reg->bg], last_reg->len);
+			len -= last_reg->len;
+			if (reg) {
+				reg->next = NULL;
+			} else {
+				alloc->list.first = NULL;
+				alloc->list.last = NULL;
+				alloc->list.iter = NULL;
+				alloc->list.partial_iter = 0;
+			}
+			free(last_reg);
+		}
+	}
+}
+
+static void init_bg(struct block_group_info *bg, unsigned int i)
+{
+	int header_blocks = 2 + aux_info.inode_table_blocks;
+
+	bg->has_superblock = ext4_bg_has_super_block(i);
+
+	if (bg->has_superblock)
+		header_blocks += 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
+
+	bg->bitmaps = calloc(info.block_size, 2);
+	bg->block_bitmap = bg->bitmaps;
+	bg->inode_bitmap = bg->bitmaps + info.block_size;
+
+	bg->header_blocks = header_blocks;
+	bg->first_block = aux_info.first_data_block + i * info.blocks_per_group;
+
+	u32 block = bg->first_block;
+	if (bg->has_superblock)
+		block += 1 + aux_info.bg_desc_blocks +  info.bg_desc_reserve_blocks;
+	sparse_file_add_data(ext4_sparse_file, bg->bitmaps, 2 * info.block_size,
+			block);
+
+	bg->data_blocks_used = 0;
+	bg->free_blocks = info.blocks_per_group;
+	bg->first_free_block = 0;
+	bg->free_inodes = info.inodes_per_group;
+	bg->first_free_inode = 1;
+	bg->flags = EXT4_BG_INODE_UNINIT;
+
+	if (reserve_blocks(bg, bg->first_free_block, bg->header_blocks) < 0)
+		error("failed to reserve %u blocks in block group %u\n", bg->header_blocks, i);
+
+	if (bg->first_block + info.blocks_per_group > aux_info.len_blocks) {
+		u32 overrun = bg->first_block + info.blocks_per_group - aux_info.len_blocks;
+		reserve_blocks(bg, info.blocks_per_group - overrun, overrun);
+	}
+}
+
+void block_allocator_init()
+{
+	unsigned int i;
+
+	aux_info.bgs = calloc(sizeof(struct block_group_info), aux_info.groups);
+	if (aux_info.bgs == NULL)
+		critical_error_errno("calloc");
+
+	for (i = 0; i < aux_info.groups; i++)
+		init_bg(&aux_info.bgs[i], i);
+}
+
+void block_allocator_free()
+{
+	unsigned int i;
+
+	for (i = 0; i < aux_info.groups; i++) {
+		free(aux_info.bgs[i].bitmaps);
+		free(aux_info.bgs[i].inode_table);
+	}
+	free(aux_info.bgs);
+}
+
+static u32 ext4_allocate_blocks_from_block_group(u32 len, int bg_num)
+{
+	if (get_free_blocks(bg_num) < len)
+		return EXT4_ALLOCATE_FAILED;
+
+	u32 block = aux_info.bgs[bg_num].first_free_block;
+	struct block_group_info *bg = &aux_info.bgs[bg_num];
+	if (reserve_blocks(bg, bg->first_free_block, len) < 0) {
+		error("failed to reserve %u blocks in block group %u\n", len, bg_num);
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	aux_info.bgs[bg_num].data_blocks_used += len;
+
+	return bg->first_block + block;
+}
+
+/* Allocate a single block and return its block number */
+u32 allocate_block()
+{
+	unsigned int i;
+	for (i = 0; i < aux_info.groups; i++) {
+		u32 block = ext4_allocate_blocks_from_block_group(1, i);
+
+		if (block != EXT4_ALLOCATE_FAILED)
+			return block;
+	}
+
+	return EXT4_ALLOCATE_FAILED;
+}
+
+static struct region *ext4_allocate_best_fit_partial(u32 len)
+{
+	unsigned int i;
+	unsigned int found_bg = 0;
+	u32 found_bg_len = 0;
+
+	for (i = 0; i < aux_info.groups; i++) {
+		u32 bg_len = aux_info.bgs[i].free_blocks;
+
+		if ((len <= bg_len && (found_bg_len == 0 || bg_len < found_bg_len)) ||
+		    (len > found_bg_len && bg_len > found_bg_len)) {
+			found_bg = i;
+			found_bg_len = bg_len;
+		}
+	}
+
+	if (found_bg_len) {
+		u32 allocate_len = min(len, found_bg_len);
+		struct region *reg;
+		u32 block = ext4_allocate_blocks_from_block_group(allocate_len, found_bg);
+		if (block == EXT4_ALLOCATE_FAILED) {
+			error("failed to allocate %d blocks in block group %d", allocate_len, found_bg);
+			return NULL;
+		}
+		reg = malloc(sizeof(struct region));
+		reg->block = block;
+		reg->len = allocate_len;
+		reg->next = NULL;
+		reg->prev = NULL;
+		reg->bg = found_bg;
+		return reg;
+	} else {
+		error("failed to allocate %u blocks, out of space?", len);
+	}
+
+	return NULL;
+}
+
+static struct region *ext4_allocate_best_fit(u32 len)
+{
+	struct region *first_reg = NULL;
+	struct region *prev_reg = NULL;
+	struct region *reg;
+
+	while (len > 0) {
+		reg = ext4_allocate_best_fit_partial(len);
+		if (reg == NULL)
+			return NULL;
+
+		if (first_reg == NULL)
+			first_reg = reg;
+
+		if (prev_reg) {
+			prev_reg->next = reg;
+			reg->prev = prev_reg;
+		}
+
+		prev_reg = reg;
+		len -= reg->len;
+	}
+
+	return first_reg;
+}
+
+/* Allocate len blocks.  The blocks may be spread across multiple block groups,
+   and are returned in a linked list of the blocks in each block group.  The
+   allocation algorithm is:
+      1.  If the remaining allocation is larger than any available contiguous region,
+          allocate the largest contiguous region and loop
+      2.  Otherwise, allocate the smallest contiguous region that it fits in
+*/
+struct block_allocation *allocate_blocks(u32 len)
+{
+	struct region *reg = ext4_allocate_best_fit(len);
+
+	if (reg == NULL)
+		return NULL;
+
+	struct block_allocation *alloc = create_allocation();
+	alloc->list.first = reg;
+	alloc->list.last = reg;
+	alloc->list.iter = alloc->list.first;
+	alloc->list.partial_iter = 0;
+	return alloc;
+}
+
+/* Returns the number of discontiguous regions used by an allocation */
+int block_allocation_num_regions(struct block_allocation *alloc)
+{
+	unsigned int i;
+	struct region *reg = alloc->list.first;
+
+	for (i = 0; reg != NULL; reg = reg->next)
+		i++;
+
+	return i;
+}
+
+int block_allocation_len(struct block_allocation *alloc)
+{
+	unsigned int i;
+	struct region *reg = alloc->list.first;
+
+	for (i = 0; reg != NULL; reg = reg->next)
+		i += reg->len;
+
+	return i;
+}
+
+/* Returns the block number of the block'th block in an allocation */
+u32 get_block(struct block_allocation *alloc, u32 block)
+{
+	struct region *reg = alloc->list.iter;
+	block += alloc->list.partial_iter;
+
+	for (; reg; reg = reg->next) {
+		if (block < reg->len)
+			return reg->block + block;
+		block -= reg->len;
+	}
+	return EXT4_ALLOCATE_FAILED;
+}
+
+u32 get_oob_block(struct block_allocation *alloc, u32 block)
+{
+	struct region *reg = alloc->oob_list.iter;
+	block += alloc->oob_list.partial_iter;
+
+	for (; reg; reg = reg->next) {
+		if (block < reg->len)
+			return reg->block + block;
+		block -= reg->len;
+	}
+	return EXT4_ALLOCATE_FAILED;
+}
+
+/* Gets the starting block and length in blocks of the first region
+   of an allocation */
+void get_region(struct block_allocation *alloc, u32 *block, u32 *len)
+{
+	*block = alloc->list.iter->block;
+	*len = alloc->list.iter->len - alloc->list.partial_iter;
+}
+
+/* Move to the next region in an allocation */
+void get_next_region(struct block_allocation *alloc)
+{
+	alloc->list.iter = alloc->list.iter->next;
+	alloc->list.partial_iter = 0;
+}
+
+/* Returns the number of free blocks in a block group */
+u32 get_free_blocks(u32 bg)
+{
+	return aux_info.bgs[bg].free_blocks;
+}
+
+int last_region(struct block_allocation *alloc)
+{
+	return (alloc->list.iter == NULL);
+}
+
+void rewind_alloc(struct block_allocation *alloc)
+{
+	alloc->list.iter = alloc->list.first;
+	alloc->list.partial_iter = 0;
+}
+
+static struct region *do_split_allocation(struct block_allocation *alloc, u32 len)
+{
+	struct region *reg = alloc->list.iter;
+	struct region *new;
+	struct region *tmp;
+
+	while (reg && len >= reg->len) {
+		len -= reg->len;
+		reg = reg->next;
+	}
+
+	if (reg == NULL && len > 0)
+		return NULL;
+
+	if (len > 0) {
+		new = malloc(sizeof(struct region));
+
+		new->bg = reg->bg;
+		new->block = reg->block + len;
+		new->len = reg->len - len;
+		new->next = reg->next;
+		new->prev = reg;
+
+		reg->next = new;
+		reg->len = len;
+
+		tmp = alloc->list.iter;
+		alloc->list.iter = new;
+		return tmp;
+	} else {
+		return reg;
+	}
+}
+
+/* Splits an allocation into two allocations.  The returned allocation will
+   point to the first half, and the original allocation ptr will point to the
+   second half. */
+static struct region *split_allocation(struct block_allocation *alloc, u32 len)
+{
+	/* First make sure there is a split at the current ptr */
+	do_split_allocation(alloc, alloc->list.partial_iter);
+
+	/* Then split off len blocks */
+	struct region *middle = do_split_allocation(alloc, len);
+	alloc->list.partial_iter = 0;
+	return middle;
+}
+
+/* Reserve the next blocks for oob data (indirect or extent blocks) */
+int reserve_oob_blocks(struct block_allocation *alloc, int blocks)
+{
+	struct region *oob = split_allocation(alloc, blocks);
+	struct region *next;
+
+	if (oob == NULL)
+		return -1;
+
+	while (oob && oob != alloc->list.iter) {
+		next = oob->next;
+		region_list_remove(&alloc->list, oob);
+		region_list_append(&alloc->oob_list, oob);
+		oob = next;
+	}
+
+	return 0;
+}
+
+static int advance_list_ptr(struct region_list *list, int blocks)
+{
+	struct region *reg = list->iter;
+
+	while (reg != NULL && blocks > 0) {
+		if (reg->len > list->partial_iter + blocks) {
+			list->partial_iter += blocks;
+			return 0;
+		}
+
+		blocks -= (reg->len - list->partial_iter);
+		list->partial_iter = 0;
+		reg = reg->next;
+	}
+
+	if (blocks > 0)
+		return -1;
+
+	return 0;
+}
+
+/* Move the allocation pointer forward */
+int advance_blocks(struct block_allocation *alloc, int blocks)
+{
+	return advance_list_ptr(&alloc->list, blocks);
+}
+
+int advance_oob_blocks(struct block_allocation *alloc, int blocks)
+{
+	return advance_list_ptr(&alloc->oob_list, blocks);
+}
+
+int append_oob_allocation(struct block_allocation *alloc, u32 len)
+{
+	struct region *reg = ext4_allocate_best_fit(len);
+
+	if (reg == NULL) {
+		error("failed to allocate %d blocks", len);
+		return -1;
+	}
+
+	for (; reg; reg = reg->next)
+		region_list_append(&alloc->oob_list, reg);
+
+	return 0;
+}
+
+/* Returns an ext4_inode structure for an inode number */
+struct ext4_inode *get_inode(u32 inode)
+{
+	inode -= 1;
+	int bg = inode / info.inodes_per_group;
+	inode %= info.inodes_per_group;
+
+	allocate_bg_inode_table(&aux_info.bgs[bg]);
+	return (struct ext4_inode *)(aux_info.bgs[bg].inode_table + inode *
+		info.inode_size);
+}
+
+struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode)
+{
+	struct ext4_xattr_header *block = xattr_list_find(inode);
+	if (block != NULL)
+		return block;
+
+	u32 block_num = allocate_block();
+	block = calloc(info.block_size, 1);
+	if (block == NULL) {
+		error("get_xattr: failed to allocate %d", info.block_size);
+		return NULL;
+	}
+
+	block->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
+	block->h_refcount = cpu_to_le32(1);
+	block->h_blocks = cpu_to_le32(1);
+	inode->i_blocks_lo = cpu_to_le32(le32_to_cpu(inode->i_blocks_lo) + (info.block_size / 512));
+	inode->i_file_acl_lo = cpu_to_le32(block_num);
+
+	int result = sparse_file_add_data(ext4_sparse_file, block, info.block_size, block_num);
+	if (result != 0) {
+		error("get_xattr: sparse_file_add_data failure %d", result);
+		free(block);
+		return NULL;
+	}
+	xattr_list_insert(inode, block);
+	return block;
+}
+
+/* Mark the first len inodes in a block group as used */
+u32 reserve_inodes(int bg, u32 num)
+{
+	unsigned int i;
+	u32 inode;
+
+	if (get_free_inodes(bg) < num)
+		return EXT4_ALLOCATE_FAILED;
+
+	for (i = 0; i < num; i++) {
+		inode = aux_info.bgs[bg].first_free_inode + i - 1;
+		aux_info.bgs[bg].inode_bitmap[inode / 8] |= 1 << (inode % 8);
+	}
+
+	inode = aux_info.bgs[bg].first_free_inode;
+
+	aux_info.bgs[bg].first_free_inode += num;
+	aux_info.bgs[bg].free_inodes -= num;
+
+	return inode;
+}
+
+/* Returns the first free inode number
+   TODO: Inodes should be allocated in the block group of the data? */
+u32 allocate_inode()
+{
+	unsigned int bg;
+	u32 inode;
+
+	for (bg = 0; bg < aux_info.groups; bg++) {
+		inode = reserve_inodes(bg, 1);
+		if (inode != EXT4_ALLOCATE_FAILED)
+			return bg * info.inodes_per_group + inode;
+	}
+
+	return EXT4_ALLOCATE_FAILED;
+}
+
+/* Returns the number of free inodes in a block group */
+u32 get_free_inodes(u32 bg)
+{
+	return aux_info.bgs[bg].free_inodes;
+}
+
+/* Increments the directory count of the block group that contains inode */
+void add_directory(u32 inode)
+{
+	int bg = (inode - 1) / info.inodes_per_group;
+	aux_info.bgs[bg].used_dirs += 1;
+}
+
+/* Returns the number of inodes in a block group that are directories */
+u16 get_directories(int bg)
+{
+	return aux_info.bgs[bg].used_dirs;
+}
+
+/* Returns the flags for a block group */
+u16 get_bg_flags(int bg)
+{
+	return aux_info.bgs[bg].flags;
+}
+
+/* Frees the memory used by a linked list of allocation regions */
+void free_alloc(struct block_allocation *alloc)
+{
+	struct region *reg;
+
+	reg = alloc->list.first;
+	while (reg) {
+		struct region *next = reg->next;
+		free(reg);
+		reg = next;
+	}
+
+	reg = alloc->oob_list.first;
+	while (reg) {
+		struct region *next = reg->next;
+		free(reg);
+		reg = next;
+	}
+
+	free(alloc);
+}
diff --git a/distrib/ext4_utils/src/allocate.h b/distrib/ext4_utils/src/allocate.h
new file mode 100644
index 0000000..a0999e4
--- /dev/null
+++ b/distrib/ext4_utils/src/allocate.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _ALLOCATE_H_
+#define _ALLOCATE_H_
+
+#define EXT4_ALLOCATE_FAILED (u32)(~0)
+
+#include "ext4_utils.h"
+
+struct block_allocation;
+
+void block_allocator_init();
+void block_allocator_free();
+u32 allocate_block();
+struct block_allocation *allocate_blocks(u32 len);
+int block_allocation_num_regions(struct block_allocation *alloc);
+int block_allocation_len(struct block_allocation *alloc);
+struct ext4_inode *get_inode(u32 inode);
+struct ext4_xattr_header *get_xattr_block_for_inode(struct ext4_inode *inode);
+void reduce_allocation(struct block_allocation *alloc, u32 len);
+u32 get_block(struct block_allocation *alloc, u32 block);
+u32 get_oob_block(struct block_allocation *alloc, u32 block);
+void get_next_region(struct block_allocation *alloc);
+void get_region(struct block_allocation *alloc, u32 *block, u32 *len);
+u32 get_free_blocks(u32 bg);
+u32 get_free_inodes(u32 bg);
+u32 reserve_inodes(int bg, u32 inodes);
+void add_directory(u32 inode);
+u16 get_directories(int bg);
+u16 get_bg_flags(int bg);
+void init_unused_inode_tables(void);
+u32 allocate_inode();
+void free_alloc(struct block_allocation *alloc);
+int reserve_oob_blocks(struct block_allocation *alloc, int blocks);
+int advance_blocks(struct block_allocation *alloc, int blocks);
+int advance_oob_blocks(struct block_allocation *alloc, int blocks);
+int last_region(struct block_allocation *alloc);
+void rewind_alloc(struct block_allocation *alloc);
+void append_region(struct block_allocation *alloc,
+	u32 block, u32 len, int bg);
+struct block_allocation *create_allocation();
+int append_oob_allocation(struct block_allocation *alloc, u32 len);
+
+#endif
diff --git a/distrib/ext4_utils/src/contents.c b/distrib/ext4_utils/src/contents.c
new file mode 100644
index 0000000..80e5692
--- /dev/null
+++ b/distrib/ext4_utils/src/contents.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright (C) 2010 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 <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_ANDROID_OS
+#include <linux/capability.h>
+#else
+#include <private/android_filesystem_capability.h>
+#endif
+
+#define XATTR_SELINUX_SUFFIX "selinux"
+#define XATTR_CAPS_SUFFIX "capability"
+
+#include "ext4_utils.h"
+#include "make_ext4fs.h"
+#include "allocate.h"
+#include "contents.h"
+#include "extent.h"
+#include "indirect.h"
+
+#ifdef USE_MINGW
+#define S_IFLNK 0  /* used by make_link, not needed under mingw */
+#endif
+
+static u32 dentry_size(u32 entries, struct dentry *dentries)
+{
+	u32 len = 24;
+	unsigned int i;
+	unsigned int dentry_len;
+
+	for (i = 0; i < entries; i++) {
+		dentry_len = 8 + ALIGN(strlen(dentries[i].filename), 4);
+		if (len % info.block_size + dentry_len > info.block_size)
+			len += info.block_size - (len % info.block_size);
+		len += dentry_len;
+	}
+
+	return len;
+}
+
+static struct ext4_dir_entry_2 *add_dentry(u8 *data, u32 *offset,
+		struct ext4_dir_entry_2 *prev, u32 inode, const char *name,
+		u8 file_type)
+{
+	u8 name_len = strlen(name);
+	u16 rec_len = 8 + ALIGN(name_len, 4);
+	struct ext4_dir_entry_2 *dentry;
+
+	u32 start_block = *offset / info.block_size;
+	u32 end_block = (*offset + rec_len - 1) / info.block_size;
+	if (start_block != end_block) {
+		/* Adding this dentry will cross a block boundary, so pad the previous
+		   dentry to the block boundary */
+		if (!prev)
+			critical_error("no prev");
+		prev->rec_len += end_block * info.block_size - *offset;
+		*offset = end_block * info.block_size;
+	}
+
+	dentry = (struct ext4_dir_entry_2 *)(data + *offset);
+	dentry->inode = inode;
+	dentry->rec_len = rec_len;
+	dentry->name_len = name_len;
+	dentry->file_type = file_type;
+	memcpy(dentry->name, name, name_len);
+
+	*offset += rec_len;
+	return dentry;
+}
+
+/* Creates a directory structure for an array of directory entries, dentries,
+   and stores the location of the structure in an inode.  The new inode's
+   .. link is set to dir_inode_num.  Stores the location of the inode number
+   of each directory entry into dentries[i].inode, to be filled in later
+   when the inode for the entry is allocated.  Returns the inode number of the
+   new directory */
+u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
+	u32 dirs)
+{
+	struct ext4_inode *inode;
+	u32 blocks;
+	u32 len;
+	u32 offset = 0;
+	u32 inode_num;
+	u8 *data;
+	unsigned int i;
+	struct ext4_dir_entry_2 *dentry;
+
+	blocks = DIV_ROUND_UP(dentry_size(entries, dentries), info.block_size);
+	len = blocks * info.block_size;
+
+	if (dir_inode_num) {
+		inode_num = allocate_inode(info);
+	} else {
+		dir_inode_num = EXT4_ROOT_INO;
+		inode_num = EXT4_ROOT_INO;
+	}
+
+	if (inode_num == EXT4_ALLOCATE_FAILED) {
+		error("failed to allocate inode\n");
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	add_directory(inode_num);
+
+	inode = get_inode(inode_num);
+	if (inode == NULL) {
+		error("failed to get inode %u", inode_num);
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	data = inode_allocate_data_extents(inode, len, len);
+	if (data == NULL) {
+		error("failed to allocate %u extents", len);
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	inode->i_mode = S_IFDIR;
+	inode->i_links_count = dirs + 2;
+	inode->i_flags |= aux_info.default_i_flags;
+
+	dentry = NULL;
+
+	dentry = add_dentry(data, &offset, NULL, inode_num, ".", EXT4_FT_DIR);
+	if (!dentry) {
+		error("failed to add . directory");
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	dentry = add_dentry(data, &offset, dentry, dir_inode_num, "..", EXT4_FT_DIR);
+	if (!dentry) {
+		error("failed to add .. directory");
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	for (i = 0; i < entries; i++) {
+		dentry = add_dentry(data, &offset, dentry, 0,
+				dentries[i].filename, dentries[i].file_type);
+		if (offset > len || (offset == len && i != entries - 1))
+			critical_error("internal error: dentry for %s ends at %d, past %d\n",
+				dentries[i].filename, offset, len);
+		dentries[i].inode = &dentry->inode;
+		if (!dentry) {
+			error("failed to add directory");
+			return EXT4_ALLOCATE_FAILED;
+		}
+	}
+
+	/* pad the last dentry out to the end of the block */
+	dentry->rec_len += len - offset;
+
+	return inode_num;
+}
+
+/* Creates a file on disk.  Returns the inode number of the new file */
+u32 make_file(const char *filename, u64 len)
+{
+	struct ext4_inode *inode;
+	u32 inode_num;
+
+	inode_num = allocate_inode(info);
+	if (inode_num == EXT4_ALLOCATE_FAILED) {
+		error("failed to allocate inode\n");
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	inode = get_inode(inode_num);
+	if (inode == NULL) {
+		error("failed to get inode %u", inode_num);
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	if (len > 0)
+		inode_allocate_file_extents(inode, len, filename);
+
+	inode->i_mode = S_IFREG;
+	inode->i_links_count = 1;
+	inode->i_flags |= aux_info.default_i_flags;
+
+	return inode_num;
+}
+
+/* Creates a file on disk.  Returns the inode number of the new file */
+u32 make_link(const char *link)
+{
+	struct ext4_inode *inode;
+	u32 inode_num;
+	u32 len = strlen(link);
+
+	inode_num = allocate_inode(info);
+	if (inode_num == EXT4_ALLOCATE_FAILED) {
+		error("failed to allocate inode\n");
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	inode = get_inode(inode_num);
+	if (inode == NULL) {
+		error("failed to get inode %u", inode_num);
+		return EXT4_ALLOCATE_FAILED;
+	}
+
+	inode->i_mode = S_IFLNK;
+	inode->i_links_count = 1;
+	inode->i_flags |= aux_info.default_i_flags;
+	inode->i_size_lo = len;
+
+	if (len + 1 <= sizeof(inode->i_block)) {
+		/* Fast symlink */
+		memcpy((char*)inode->i_block, link, len);
+	} else {
+		u8 *data = inode_allocate_data_indirect(inode, info.block_size, info.block_size);
+		memcpy(data, link, len);
+		inode->i_blocks_lo = info.block_size / 512;
+	}
+
+	return inode_num;
+}
+
+int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime)
+{
+	struct ext4_inode *inode = get_inode(inode_num);
+
+	if (!inode)
+		return -1;
+
+	inode->i_mode |= mode;
+	inode->i_uid = uid;
+	inode->i_gid = gid;
+	inode->i_mtime = mtime;
+	inode->i_atime = mtime;
+	inode->i_ctime = mtime;
+
+	return 0;
+}
+
+/*
+ * Returns the amount of free space available in the specified
+ * xattr region
+ */
+static size_t xattr_free_space(struct ext4_xattr_entry *entry, char *end)
+{
+	while(!IS_LAST_ENTRY(entry) && (((char *) entry) < end)) {
+		end   -= EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size));
+		entry  = EXT4_XATTR_NEXT(entry);
+	}
+
+	if (((char *) entry) > end) {
+		error("unexpected read beyond end of xattr space");
+		return 0;
+	}
+
+	return end - ((char *) entry);
+}
+
+/*
+ * Returns a pointer to the free space immediately after the
+ * last xattr element
+ */
+static struct ext4_xattr_entry* xattr_get_last(struct ext4_xattr_entry *entry)
+{
+	for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+		// skip entry
+	}
+	return entry;
+}
+
+/*
+ * assert that the elements in the ext4 xattr section are in sorted order
+ *
+ * The ext4 filesystem requires extended attributes to be sorted when
+ * they're not stored in the inode. The kernel ext4 code uses the following
+ * sorting algorithm:
+ *
+ * 1) First sort extended attributes by their name_index. For example,
+ *    EXT4_XATTR_INDEX_USER (1) comes before EXT4_XATTR_INDEX_SECURITY (6).
+ * 2) If the name_indexes are equal, then sorting is based on the length
+ *    of the name. For example, XATTR_SELINUX_SUFFIX ("selinux") comes before
+ *    XATTR_CAPS_SUFFIX ("capability") because "selinux" is shorter than "capability"
+ * 3) If the name_index and name_length are equal, then memcmp() is used to determine
+ *    which name comes first. For example, "selinux" would come before "yelinux".
+ *
+ * This method is intended to implement the sorting function defined in
+ * the Linux kernel file fs/ext4/xattr.c function ext4_xattr_find_entry().
+ */
+static void xattr_assert_sane(struct ext4_xattr_entry *entry)
+{
+	for( ; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) {
+		struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(entry);
+		if (IS_LAST_ENTRY(next)) {
+			return;
+		}
+
+		int cmp = next->e_name_index - entry->e_name_index;
+		if (cmp == 0)
+			cmp = next->e_name_len - entry->e_name_len;
+		if (cmp == 0)
+			cmp = memcmp(next->e_name, entry->e_name, next->e_name_len);
+		if (cmp < 0) {
+			error("BUG: extended attributes are not sorted\n");
+			return;
+		}
+		if (cmp == 0) {
+			error("BUG: duplicate extended attributes detected\n");
+			return;
+		}
+	}
+}
+
+#define NAME_HASH_SHIFT 5
+#define VALUE_HASH_SHIFT 16
+
+static void ext4_xattr_hash_entry(struct ext4_xattr_header *header,
+		struct ext4_xattr_entry *entry)
+{
+	u32 hash = 0;
+	char *name = entry->e_name;
+	int n;
+
+	for (n = 0; n < entry->e_name_len; n++) {
+		hash = (hash << NAME_HASH_SHIFT) ^
+			(hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^
+			*name++;
+	}
+
+	if (entry->e_value_block == 0 && entry->e_value_size != 0) {
+		u32 *value = (u32 *)((char *)header +
+			le16_to_cpu(entry->e_value_offs));
+		for (n = (le32_to_cpu(entry->e_value_size) +
+			EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) {
+			hash = (hash << VALUE_HASH_SHIFT) ^
+				(hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^
+				le32_to_cpu(*value++);
+		}
+	}
+	entry->e_hash = cpu_to_le32(hash);
+}
+
+#undef NAME_HASH_SHIFT
+#undef VALUE_HASH_SHIFT
+
+static struct ext4_xattr_entry* xattr_addto_range(
+		void *block_start,
+		void *block_end,
+		struct ext4_xattr_entry *first,
+		int name_index,
+		const char *name,
+		const void *value,
+		size_t value_len)
+{
+	size_t name_len = strlen(name);
+	if (name_len > 255)
+		return NULL;
+
+	size_t available_size = xattr_free_space(first, block_end);
+	size_t needed_size = EXT4_XATTR_LEN(name_len) + EXT4_XATTR_SIZE(value_len);
+
+	if (needed_size > available_size)
+		return NULL;
+
+	struct ext4_xattr_entry *new_entry = xattr_get_last(first);
+	memset(new_entry, 0, EXT4_XATTR_LEN(name_len));
+
+	new_entry->e_name_len = name_len;
+	new_entry->e_name_index = name_index;
+	memcpy(new_entry->e_name, name, name_len);
+	new_entry->e_value_block = 0;
+	new_entry->e_value_size = cpu_to_le32(value_len);
+
+	char *val = (char *) new_entry + available_size - EXT4_XATTR_SIZE(value_len);
+	size_t e_value_offs = val - (char *) block_start;
+
+	new_entry->e_value_offs = cpu_to_le16(e_value_offs);
+	memset(val, 0, EXT4_XATTR_SIZE(value_len));
+	memcpy(val, value, value_len);
+
+	xattr_assert_sane(first);
+	return new_entry;
+}
+
+static int xattr_addto_inode(struct ext4_inode *inode, int name_index,
+		const char *name, const void *value, size_t value_len)
+{
+	struct ext4_xattr_ibody_header *hdr = (struct ext4_xattr_ibody_header *) (inode + 1);
+	struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (hdr + 1);
+	char *block_end = ((char *) inode) + info.inode_size;
+
+	struct ext4_xattr_entry *result =
+		xattr_addto_range(first, block_end, first, name_index, name, value, value_len);
+
+	if (result == NULL)
+		return -1;
+
+	hdr->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC);
+	inode->i_extra_isize = cpu_to_le16(sizeof(struct ext4_inode) - EXT4_GOOD_OLD_INODE_SIZE);
+
+	return 0;
+}
+
+static int xattr_addto_block(struct ext4_inode *inode, int name_index,
+		const char *name, const void *value, size_t value_len)
+{
+	struct ext4_xattr_header *header = get_xattr_block_for_inode(inode);
+	if (!header)
+		return -1;
+
+	struct ext4_xattr_entry *first = (struct ext4_xattr_entry *) (header + 1);
+	char *block_end = ((char *) header) + info.block_size;
+
+	struct ext4_xattr_entry *result =
+		xattr_addto_range(header, block_end, first, name_index, name, value, value_len);
+
+	if (result == NULL)
+		return -1;
+
+	ext4_xattr_hash_entry(header, result);
+	return 0;
+}
+
+
+static int xattr_add(u32 inode_num, int name_index, const char *name,
+		const void *value, size_t value_len)
+{
+	if (!value)
+		return 0;
+
+	struct ext4_inode *inode = get_inode(inode_num);
+
+	if (!inode)
+		return -1;
+
+	int result = xattr_addto_inode(inode, name_index, name, value, value_len);
+	if (result != 0) {
+		result = xattr_addto_block(inode, name_index, name, value, value_len);
+	}
+	return result;
+}
+
+int inode_set_selinux(u32 inode_num, const char *secon)
+{
+	if (!secon)
+		return 0;
+
+	return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
+		XATTR_SELINUX_SUFFIX, secon, strlen(secon) + 1);
+}
+
+int inode_set_capabilities(u32 inode_num, uint64_t capabilities) {
+	if (capabilities == 0)
+		return 0;
+
+	struct vfs_cap_data cap_data;
+	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[0].inheritable = 0;
+	cap_data.data[1].permitted = (uint32_t) (capabilities >> 32);
+	cap_data.data[1].inheritable = 0;
+
+	return xattr_add(inode_num, EXT4_XATTR_INDEX_SECURITY,
+		XATTR_CAPS_SUFFIX, &cap_data, sizeof(cap_data));
+}
+
diff --git a/distrib/ext4_utils/src/contents.h b/distrib/ext4_utils/src/contents.h
new file mode 100644
index 0000000..4272000
--- /dev/null
+++ b/distrib/ext4_utils/src/contents.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _DIRECTORY_H_
+#define _DIRECTORY_H_
+
+struct dentry {
+	char *path;
+	char *full_path;
+	const char *filename;
+	char *link;
+	unsigned long size;
+	u8 file_type;
+	u16 mode;
+	u16 uid;
+	u16 gid;
+	u32 *inode;
+	u32 mtime;
+	char *secon;
+	uint64_t capabilities;
+};
+
+u32 make_directory(u32 dir_inode_num, u32 entries, struct dentry *dentries,
+	u32 dirs);
+u32 make_file(const char *filename, u64 len);
+u32 make_link(const char *link);
+int inode_set_permissions(u32 inode_num, u16 mode, u16 uid, u16 gid, u32 mtime);
+int inode_set_selinux(u32 inode_num, const char *secon);
+int inode_set_capabilities(u32 inode_num, uint64_t capabilities);
+#endif
diff --git a/distrib/ext4_utils/src/crc16.c b/distrib/ext4_utils/src/crc16.c
new file mode 100644
index 0000000..2575812
--- /dev/null
+++ b/distrib/ext4_utils/src/crc16.c
@@ -0,0 +1,58 @@
+/*-
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ */
+
+/* CRC32 code derived from work by Gary S. Brown. */
+
+/* Code taken from FreeBSD 8 */
+
+/* Converted to crc16 */
+
+#include "ext4_utils.h"
+
+static u16 crc16_tab[] = {
+		0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+		0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+		0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+		0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+		0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+		0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+		0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+		0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+		0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+		0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+		0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+		0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+		0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+		0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+		0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+		0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+		0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+		0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+		0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+		0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+		0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+		0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+		0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+		0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+		0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+		0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+		0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+		0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+		0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+		0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+		0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+		0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
+};
+
+u16 ext4_crc16(u16 crc_in, const void *buf, int size)
+{
+        const u8 *p = buf;
+        u16 crc = crc_in;
+
+        while (size--)
+                crc = crc16_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+
+        return crc;
+}
diff --git a/distrib/ext4_utils/src/ext2simg.c b/distrib/ext4_utils/src/ext2simg.c
new file mode 100644
index 0000000..1531f0b
--- /dev/null
+++ b/distrib/ext4_utils/src/ext2simg.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+
+#include "ext4_utils.h"
+#include "make_ext4fs.h"
+#include "allocate.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define off64_t off_t
+#endif
+
+#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
+#define O_BINARY 0
+#endif
+
+extern struct fs_info info;
+
+static int verbose = 0;
+
+static void usage(char *path)
+{
+	fprintf(stderr, "%s [ options ] <image or block device> <output image>\n", path);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "  -c include CRC block\n");
+	fprintf(stderr, "  -v verbose output\n");
+	fprintf(stderr, "  -z gzip output\n");
+	fprintf(stderr, "  -S don't use sparse output format\n");
+}
+
+static int read_ext(int fd)
+{
+	off64_t ret;
+	struct ext4_super_block sb;
+
+	ret = lseek64(fd, 1024, SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to superblock");
+
+	ret = read(fd, &sb, sizeof(sb));
+	if (ret < 0)
+		critical_error_errno("failed to read superblock");
+	if (ret != sizeof(sb))
+		critical_error("failed to read all of superblock");
+
+	ext4_parse_sb_info(&sb);
+
+	ret = lseek64(fd, info.len, SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to end of input image");
+
+	ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
+	if (ret < 0)
+		critical_error_errno("failed to seek to block group descriptors");
+
+	ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
+	if (ret < 0)
+		critical_error_errno("failed to read block group descriptors");
+	if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
+		critical_error("failed to read all of block group descriptors");
+
+	if (verbose) {
+		printf("Found filesystem with parameters:\n");
+		printf("    Size: %"PRIu64"\n", info.len);
+		printf("    Block size: %d\n", info.block_size);
+		printf("    Blocks per group: %d\n", info.blocks_per_group);
+		printf("    Inodes per group: %d\n", info.inodes_per_group);
+		printf("    Inode size: %d\n", info.inode_size);
+		printf("    Label: %s\n", info.label);
+		printf("    Blocks: %"PRIu64"\n", aux_info.len_blocks);
+		printf("    Block groups: %d\n", aux_info.groups);
+		printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+		printf("    Used %d/%d inodes and %d/%d blocks\n",
+				aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
+				aux_info.sb->s_inodes_count,
+				aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
+				aux_info.sb->s_blocks_count_lo);
+	}
+
+	return 0;
+}
+
+static int bitmap_get_bit(u8 *bitmap, u32 bit)
+{
+	if (bitmap[bit / 8] & 1 << (bit % 8))
+		return 1;
+
+	return 0;
+}
+
+static int build_sparse_ext(int fd, const char *filename)
+{
+	unsigned int i;
+	unsigned int block;
+	int start_contiguous_block;
+	u8 *block_bitmap;
+	off64_t ret;
+
+	block_bitmap = malloc(info.block_size);
+	if (!block_bitmap)
+		critical_error("failed to allocate block bitmap");
+
+	if (aux_info.first_data_block > 0)
+		sparse_file_add_file(ext4_sparse_file, filename, 0,
+				info.block_size * aux_info.first_data_block, 0);
+
+	for (i = 0; i < aux_info.groups; i++) {
+		u32 first_block = aux_info.first_data_block + i * info.blocks_per_group;
+		u32 last_block = min(info.blocks_per_group, aux_info.len_blocks - first_block);
+
+		ret = lseek64(fd, (u64)info.block_size * aux_info.bg_desc[i].bg_block_bitmap,
+				SEEK_SET);
+		if (ret < 0)
+			critical_error_errno("failed to seek to block group bitmap %d", i);
+
+		ret = read(fd, block_bitmap, info.block_size);
+		if (ret < 0)
+			critical_error_errno("failed to read block group bitmap %d", i);
+		if (ret != (int)info.block_size)
+			critical_error("failed to read all of block group bitmap %d", i);
+
+		start_contiguous_block = -1;
+		for (block = 0; block < last_block; block++) {
+			if (start_contiguous_block >= 0) {
+				if (!bitmap_get_bit(block_bitmap, block)) {
+					u32 start_block = first_block + start_contiguous_block;
+					u32 len_blocks = block - start_contiguous_block;
+
+					sparse_file_add_file(ext4_sparse_file, filename,
+							(u64)info.block_size * start_block,
+							info.block_size * len_blocks, start_block);
+					start_contiguous_block = -1;
+				}
+			} else {
+				if (bitmap_get_bit(block_bitmap, block))
+					start_contiguous_block = block;
+			}
+		}
+
+		if (start_contiguous_block >= 0) {
+			u32 start_block = first_block + start_contiguous_block;
+			u32 len_blocks = last_block - start_contiguous_block;
+			sparse_file_add_file(ext4_sparse_file, filename,
+					(u64)info.block_size * start_block,
+					info.block_size * len_blocks, start_block);
+		}
+	}
+
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	int opt;
+	const char *in = NULL;
+	const char *out = NULL;
+	int gzip = 0;
+	int sparse = 1;
+	int infd, outfd;
+	int crc = 0;
+
+	while ((opt = getopt(argc, argv, "cvzS")) != -1) {
+		switch (opt) {
+		case 'c':
+			crc = 1;
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		case 'z':
+			gzip = 1;
+			break;
+		case 'S':
+			sparse = 0;
+			break;
+		}
+	}
+
+	if (optind >= argc) {
+		fprintf(stderr, "Expected image or block device after options\n");
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	in = argv[optind++];
+
+	if (optind >= argc) {
+		fprintf(stderr, "Expected output image after input image\n");
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	out = argv[optind++];
+
+	if (optind < argc) {
+		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	infd = open(in, O_RDONLY);
+
+	if (infd < 0)
+		critical_error_errno("failed to open input image");
+
+	read_ext(infd);
+
+	ext4_sparse_file = sparse_file_new(info.block_size, info.len);
+
+	build_sparse_ext(infd, in);
+
+	close(infd);
+
+	if (strcmp(out, "-")) {
+		outfd = open(out, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+		if (outfd < 0) {
+			error_errno("open");
+			return EXIT_FAILURE;
+		}
+	} else {
+		outfd = STDOUT_FILENO;
+	}
+
+	write_ext4_image(outfd, gzip, sparse, crc);
+	close(outfd);
+
+	sparse_file_destroy(ext4_sparse_file);
+
+	return 0;
+}
diff --git a/distrib/ext4_utils/src/ext4.h b/distrib/ext4_utils/src/ext4.h
new file mode 100644
index 0000000..68b5233
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4.h
@@ -0,0 +1,577 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _EXT4_H
+#define _EXT4_H
+
+#include <sys/types.h>
+
+#undef EXT4FS_DEBUG
+
+#ifdef EXT4FS_DEBUG
+#define ext4_debug(f, a...)   do {   printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:",   __FILE__, __LINE__, __func__);   printk(KERN_DEBUG f, ## a);   } while (0)
+#else
+#define ext4_debug(f, a...) do {} while (0)
+#endif
+
+#define EXT4_ERROR_INODE(inode, fmt, a...)   ext4_error_inode(__func__, (inode), (fmt), ## a);
+
+#define EXT4_ERROR_FILE(file, fmt, a...)   ext4_error_file(__func__, (file), (fmt), ## a);
+
+typedef int ext4_grpblk_t;
+
+typedef unsigned long long ext4_fsblk_t;
+
+typedef __u32 ext4_lblk_t;
+
+typedef unsigned int ext4_group_t;
+
+#define EXT4_MB_HINT_MERGE 0x0001
+
+#define EXT4_MB_HINT_RESERVED 0x0002
+
+#define EXT4_MB_HINT_METADATA 0x0004
+
+#define EXT4_MB_HINT_FIRST 0x0008
+
+#define EXT4_MB_HINT_BEST 0x0010
+
+#define EXT4_MB_HINT_DATA 0x0020
+
+#define EXT4_MB_HINT_NOPREALLOC 0x0040
+
+#define EXT4_MB_HINT_GROUP_ALLOC 0x0080
+
+#define EXT4_MB_HINT_GOAL_ONLY 0x0100
+
+#define EXT4_MB_HINT_TRY_GOAL 0x0200
+
+#define EXT4_MB_DELALLOC_RESERVED 0x0400
+
+#define EXT4_MB_STREAM_ALLOC 0x0800
+
+struct ext4_allocation_request {
+
+ struct inode *inode;
+
+ unsigned int len;
+
+ ext4_lblk_t logical;
+
+ ext4_lblk_t lleft;
+
+ ext4_lblk_t lright;
+
+ ext4_fsblk_t goal;
+
+ ext4_fsblk_t pleft;
+
+ ext4_fsblk_t pright;
+
+ unsigned int flags;
+};
+
+#define EXT4_BAD_INO 1  
+#define EXT4_ROOT_INO 2  
+#define EXT4_BOOT_LOADER_INO 5  
+#define EXT4_UNDEL_DIR_INO 6  
+#define EXT4_RESIZE_INO 7  
+#define EXT4_JOURNAL_INO 8  
+
+#define EXT4_GOOD_OLD_FIRST_INO 11
+
+#define EXT4_LINK_MAX 65000
+
+#define EXT4_MIN_BLOCK_SIZE 1024
+#define EXT4_MAX_BLOCK_SIZE 65536
+#define EXT4_MIN_BLOCK_LOG_SIZE 10
+#define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof(__u32))
+#define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ?   EXT4_GOOD_OLD_INODE_SIZE :   (s)->s_inode_size)
+#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ?   EXT4_GOOD_OLD_FIRST_INO :   (s)->s_first_ino)
+#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
+
+struct ext4_group_desc
+{
+ __le32 bg_block_bitmap_lo;
+ __le32 bg_inode_bitmap_lo;
+ __le32 bg_inode_table_lo;
+ __le16 bg_free_blocks_count_lo;
+ __le16 bg_free_inodes_count_lo;
+ __le16 bg_used_dirs_count_lo;
+ __le16 bg_flags;
+ __u32 bg_reserved[2];
+ __le16 bg_itable_unused_lo;
+ __le16 bg_checksum;
+ __le32 bg_block_bitmap_hi;
+ __le32 bg_inode_bitmap_hi;
+ __le32 bg_inode_table_hi;
+ __le16 bg_free_blocks_count_hi;
+ __le16 bg_free_inodes_count_hi;
+ __le16 bg_used_dirs_count_hi;
+ __le16 bg_itable_unused_hi;
+ __u32 bg_reserved2[3];
+};
+
+#define EXT4_BG_INODE_UNINIT 0x0001  
+#define EXT4_BG_BLOCK_UNINIT 0x0002  
+#define EXT4_BG_INODE_ZEROED 0x0004  
+
+#define EXT4_MIN_DESC_SIZE 32
+#define EXT4_MIN_DESC_SIZE_64BIT 64
+#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE
+#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size)
+#define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+#define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s))
+#define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+
+#define EXT4_NDIR_BLOCKS 12
+#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
+#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
+#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
+#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
+
+#define EXT4_SECRM_FL 0x00000001  
+#define EXT4_UNRM_FL 0x00000002  
+#define EXT4_COMPR_FL 0x00000004  
+#define EXT4_SYNC_FL 0x00000008  
+#define EXT4_IMMUTABLE_FL 0x00000010  
+#define EXT4_APPEND_FL 0x00000020  
+#define EXT4_NODUMP_FL 0x00000040  
+#define EXT4_NOATIME_FL 0x00000080  
+
+#define EXT4_DIRTY_FL 0x00000100
+#define EXT4_COMPRBLK_FL 0x00000200  
+#define EXT4_NOCOMPR_FL 0x00000400  
+#define EXT4_ECOMPR_FL 0x00000800  
+
+#define EXT4_INDEX_FL 0x00001000  
+#define EXT4_IMAGIC_FL 0x00002000  
+#define EXT4_JOURNAL_DATA_FL 0x00004000  
+#define EXT4_NOTAIL_FL 0x00008000  
+#define EXT4_DIRSYNC_FL 0x00010000  
+#define EXT4_TOPDIR_FL 0x00020000  
+#define EXT4_HUGE_FILE_FL 0x00040000  
+#define EXT4_EXTENTS_FL 0x00080000  
+#define EXT4_EA_INODE_FL 0x00200000  
+#define EXT4_EOFBLOCKS_FL 0x00400000  
+#define EXT4_RESERVED_FL 0x80000000  
+
+#define EXT4_FL_USER_VISIBLE 0x004BDFFF  
+#define EXT4_FL_USER_MODIFIABLE 0x004B80FF  
+
+#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |  EXT4_SYNC_FL | EXT4_IMMUTABLE_FL | EXT4_APPEND_FL |  EXT4_NODUMP_FL | EXT4_NOATIME_FL |  EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |  EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL)
+
+#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
+
+#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
+
+struct ext4_new_group_data {
+ __u32 group;
+ __u64 block_bitmap;
+ __u64 inode_bitmap;
+ __u64 inode_table;
+ __u32 blocks_count;
+ __u16 reserved_blocks;
+ __u16 unused;
+ __u32 free_blocks_count;
+};
+
+#define EXT4_GET_BLOCKS_CREATE 0x0001
+
+#define EXT4_GET_BLOCKS_UNINIT_EXT 0x0002
+#define EXT4_GET_BLOCKS_CREATE_UNINIT_EXT (EXT4_GET_BLOCKS_UNINIT_EXT|  EXT4_GET_BLOCKS_CREATE)
+
+#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004
+
+#define EXT4_GET_BLOCKS_PRE_IO 0x0008
+#define EXT4_GET_BLOCKS_CONVERT 0x0010
+#define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|  EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
+
+#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|  EXT4_GET_BLOCKS_CREATE_UNINIT_EXT)
+
+#define EXT4_FREE_BLOCKS_METADATA 0x0001
+#define EXT4_FREE_BLOCKS_FORGET 0x0002
+#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
+
+#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define EXT4_IOC_GETVERSION _IOR('f', 3, long)
+#define EXT4_IOC_SETVERSION _IOW('f', 4, long)
+#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
+#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
+#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
+#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
+#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+#define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input)
+#define EXT4_IOC_MIGRATE _IO('f', 9)
+
+#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12)
+#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
+
+#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define EXT4_IOC32_GETVERSION _IOR('f', 3, int)
+#define EXT4_IOC32_SETVERSION _IOW('f', 4, int)
+#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
+#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
+#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
+#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
+#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
+
+#define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF
+
+struct ext4_inode {
+ __le16 i_mode;
+ __le16 i_uid;
+ __le32 i_size_lo;
+ __le32 i_atime;
+ __le32 i_ctime;
+ __le32 i_mtime;
+ __le32 i_dtime;
+ __le16 i_gid;
+ __le16 i_links_count;
+ __le32 i_blocks_lo;
+ __le32 i_flags;
+ union {
+ struct {
+ __le32 l_i_version;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1;
+ __le32 i_block[EXT4_N_BLOCKS];
+ __le32 i_generation;
+ __le32 i_file_acl_lo;
+ __le32 i_size_high;
+ __le32 i_obso_faddr;
+ union {
+ struct {
+ __le16 l_i_blocks_high;
+ __le16 l_i_file_acl_high;
+ __le16 l_i_uid_high;
+ __le16 l_i_gid_high;
+ __u32 l_i_reserved2;
+ } linux2;
+ struct {
+ __le16 h_i_reserved1;
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __le16 h_i_reserved1;
+ __le16 m_i_file_acl_high;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2;
+ __le16 i_extra_isize;
+ __le16 i_pad1;
+ __le32 i_ctime_extra;
+ __le32 i_mtime_extra;
+ __le32 i_atime_extra;
+ __le32 i_crtime;
+ __le32 i_crtime_extra;
+ __le32 i_version_hi;
+};
+
+struct move_extent {
+ __u32 reserved;
+ __u32 donor_fd;
+ __u64 orig_start;
+ __u64 donor_start;
+ __u64 len;
+ __u64 moved_len;
+};
+
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
+
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field)   ((offsetof(typeof(*ext4_inode), field) +   sizeof((ext4_inode)->field))   <= (EXT4_GOOD_OLD_INODE_SIZE +   (einode)->i_extra_isize))  
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode)  do {   (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec);   if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))   (raw_inode)->xtime ## _extra =   ext4_encode_extra_time(&(inode)->xtime);  } while (0)
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode)  do {   if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))   (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec);   if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))   (raw_inode)->xtime ## _extra =   ext4_encode_extra_time(&(einode)->xtime);  } while (0)
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode)  do {   (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime);   if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra))   ext4_decode_extra_time(&(inode)->xtime,   raw_inode->xtime ## _extra);  } while (0)
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode)  do {   if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime))   (einode)->xtime.tv_sec =   (signed)le32_to_cpu((raw_inode)->xtime);   if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra))   ext4_decode_extra_time(&(einode)->xtime,   raw_inode->xtime ## _extra);  } while (0)
+#define i_disk_version osd1.linux1.l_i_version
+
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_file_acl_high osd2.linux2.l_i_file_acl_high
+#define i_blocks_high osd2.linux2.l_i_blocks_high
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
+#define i_reserved2 osd2.linux2.l_i_reserved2
+
+#define EXT4_VALID_FS 0x0001  
+#define EXT4_ERROR_FS 0x0002  
+#define EXT4_ORPHAN_FS 0x0004  
+
+#define EXT2_FLAGS_SIGNED_HASH 0x0001  
+#define EXT2_FLAGS_UNSIGNED_HASH 0x0002  
+#define EXT2_FLAGS_TEST_FILESYS 0x0004  
+
+#define EXT4_MOUNT_OLDALLOC 0x00002  
+#define EXT4_MOUNT_GRPID 0x00004  
+#define EXT4_MOUNT_DEBUG 0x00008  
+#define EXT4_MOUNT_ERRORS_CONT 0x00010  
+#define EXT4_MOUNT_ERRORS_RO 0x00020  
+#define EXT4_MOUNT_ERRORS_PANIC 0x00040  
+#define EXT4_MOUNT_MINIX_DF 0x00080  
+#define EXT4_MOUNT_NOLOAD 0x00100  
+#define EXT4_MOUNT_DATA_FLAGS 0x00C00  
+#define EXT4_MOUNT_JOURNAL_DATA 0x00400  
+#define EXT4_MOUNT_ORDERED_DATA 0x00800  
+#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00  
+#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000  
+#define EXT4_MOUNT_NO_UID32 0x02000  
+#define EXT4_MOUNT_XATTR_USER 0x04000  
+#define EXT4_MOUNT_POSIX_ACL 0x08000  
+#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000  
+#define EXT4_MOUNT_BARRIER 0x20000  
+#define EXT4_MOUNT_NOBH 0x40000  
+#define EXT4_MOUNT_QUOTA 0x80000  
+#define EXT4_MOUNT_USRQUOTA 0x100000  
+#define EXT4_MOUNT_GRPQUOTA 0x200000  
+#define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000  
+#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000  
+#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000  
+#define EXT4_MOUNT_I_VERSION 0x2000000  
+#define EXT4_MOUNT_DELALLOC 0x8000000  
+#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000  
+#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000  
+#define EXT4_MOUNT_DISCARD 0x40000000  
+
+#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
+#define set_opt(o, opt) o |= EXT4_MOUNT_##opt
+#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt &   EXT4_MOUNT_##opt)
+
+#define ext4_set_bit ext2_set_bit
+#define ext4_set_bit_atomic ext2_set_bit_atomic
+#define ext4_clear_bit ext2_clear_bit
+#define ext4_clear_bit_atomic ext2_clear_bit_atomic
+#define ext4_test_bit ext2_test_bit
+#define ext4_find_first_zero_bit ext2_find_first_zero_bit
+#define ext4_find_next_zero_bit ext2_find_next_zero_bit
+#define ext4_find_next_bit ext2_find_next_bit
+
+#define EXT4_DFL_MAX_MNT_COUNT 20  
+#define EXT4_DFL_CHECKINTERVAL 0  
+
+#define EXT4_ERRORS_CONTINUE 1  
+#define EXT4_ERRORS_RO 2  
+#define EXT4_ERRORS_PANIC 3  
+#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
+
+struct ext4_super_block {
+  __le32 s_inodes_count;
+ __le32 s_blocks_count_lo;
+ __le32 s_r_blocks_count_lo;
+ __le32 s_free_blocks_count_lo;
+  __le32 s_free_inodes_count;
+ __le32 s_first_data_block;
+ __le32 s_log_block_size;
+ __le32 s_obso_log_frag_size;
+  __le32 s_blocks_per_group;
+ __le32 s_obso_frags_per_group;
+ __le32 s_inodes_per_group;
+ __le32 s_mtime;
+  __le32 s_wtime;
+ __le16 s_mnt_count;
+ __le16 s_max_mnt_count;
+ __le16 s_magic;
+ __le16 s_state;
+ __le16 s_errors;
+ __le16 s_minor_rev_level;
+  __le32 s_lastcheck;
+ __le32 s_checkinterval;
+ __le32 s_creator_os;
+ __le32 s_rev_level;
+  __le16 s_def_resuid;
+ __le16 s_def_resgid;
+
+ __le32 s_first_ino;
+ __le16 s_inode_size;
+ __le16 s_block_group_nr;
+ __le32 s_feature_compat;
+  __le32 s_feature_incompat;
+ __le32 s_feature_ro_compat;
+  __u8 s_uuid[16];
+  char s_volume_name[16];
+  char s_last_mounted[64];
+  __le32 s_algorithm_usage_bitmap;
+
+ __u8 s_prealloc_blocks;
+ __u8 s_prealloc_dir_blocks;
+ __le16 s_reserved_gdt_blocks;
+
+  __u8 s_journal_uuid[16];
+  __le32 s_journal_inum;
+ __le32 s_journal_dev;
+ __le32 s_last_orphan;
+ __le32 s_hash_seed[4];
+ __u8 s_def_hash_version;
+ __u8 s_reserved_char_pad;
+ __le16 s_desc_size;
+  __le32 s_default_mount_opts;
+ __le32 s_first_meta_bg;
+ __le32 s_mkfs_time;
+ __le32 s_jnl_blocks[17];
+
+  __le32 s_blocks_count_hi;
+ __le32 s_r_blocks_count_hi;
+ __le32 s_free_blocks_count_hi;
+ __le16 s_min_extra_isize;
+ __le16 s_want_extra_isize;
+ __le32 s_flags;
+ __le16 s_raid_stride;
+ __le16 s_mmp_interval;
+ __le64 s_mmp_block;
+ __le32 s_raid_stripe_width;
+ __u8 s_log_groups_per_flex;
+ __u8 s_reserved_char_pad2;
+ __le16 s_reserved_pad;
+ __le64 s_kbytes_written;
+ __u32 s_reserved[160];
+};
+
+#define EXT4_SB(sb) (sb)
+
+#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
+
+#define EXT4_OS_LINUX 0
+#define EXT4_OS_HURD 1
+#define EXT4_OS_MASIX 2
+#define EXT4_OS_FREEBSD 3
+#define EXT4_OS_LITES 4
+
+#define EXT4_GOOD_OLD_REV 0  
+#define EXT4_DYNAMIC_REV 1  
+
+#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV
+#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+#define EXT4_HAS_COMPAT_FEATURE(sb,mask)   ((EXT4_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask)) != 0)
+#define EXT4_HAS_RO_COMPAT_FEATURE(sb,mask)   ((EXT4_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask)) != 0)
+#define EXT4_HAS_INCOMPAT_FEATURE(sb,mask)   ((EXT4_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask)) != 0)
+#define EXT4_SET_COMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT4_SET_RO_COMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT4_SET_INCOMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT4_CLEAR_COMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT4_CLEAR_RO_COMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT4_CLEAR_INCOMPAT_FEATURE(sb,mask)   EXT4_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
+
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004  
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008  
+#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040  
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400  
+#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000  
+
+#define EXT4_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR
+#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE|   EXT4_FEATURE_INCOMPAT_RECOVER|   EXT4_FEATURE_INCOMPAT_META_BG|   EXT4_FEATURE_INCOMPAT_EXTENTS|   EXT4_FEATURE_INCOMPAT_64BIT|   EXT4_FEATURE_INCOMPAT_FLEX_BG)
+#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER|   EXT4_FEATURE_RO_COMPAT_LARGE_FILE|   EXT4_FEATURE_RO_COMPAT_GDT_CSUM|   EXT4_FEATURE_RO_COMPAT_DIR_NLINK |   EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE |   EXT4_FEATURE_RO_COMPAT_BTREE_DIR |  EXT4_FEATURE_RO_COMPAT_HUGE_FILE)
+
+#define EXT4_DEF_RESUID 0
+#define EXT4_DEF_RESGID 0
+
+#define EXT4_DEF_INODE_READAHEAD_BLKS 32
+
+#define EXT4_DEFM_DEBUG 0x0001
+#define EXT4_DEFM_BSDGROUPS 0x0002
+#define EXT4_DEFM_XATTR_USER 0x0004
+#define EXT4_DEFM_ACL 0x0008
+#define EXT4_DEFM_UID16 0x0010
+#define EXT4_DEFM_JMODE 0x0060
+#define EXT4_DEFM_JMODE_DATA 0x0020
+#define EXT4_DEFM_JMODE_ORDERED 0x0040
+#define EXT4_DEFM_JMODE_WBACK 0x0060
+
+#define EXT4_DEF_MIN_BATCH_TIME 0
+#define EXT4_DEF_MAX_BATCH_TIME 15000  
+
+#define EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME 4
+
+#define EXT4_NAME_LEN 255
+
+struct ext4_dir_entry {
+ __le32 inode;
+ __le16 rec_len;
+ __le16 name_len;
+ char name[EXT4_NAME_LEN];
+};
+
+struct ext4_dir_entry_2 {
+ __le32 inode;
+ __le16 rec_len;
+ __u8 name_len;
+ __u8 file_type;
+ char name[EXT4_NAME_LEN];
+};
+
+#define EXT4_FT_UNKNOWN 0
+#define EXT4_FT_REG_FILE 1
+#define EXT4_FT_DIR 2
+#define EXT4_FT_CHRDEV 3
+#define EXT4_FT_BLKDEV 4
+#define EXT4_FT_FIFO 5
+#define EXT4_FT_SOCK 6
+#define EXT4_FT_SYMLINK 7
+
+#define EXT4_FT_MAX 8
+
+#define EXT4_DIR_PAD 4
+#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1)
+#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) &   ~EXT4_DIR_ROUND)
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
+#define is_dx(dir) (EXT4_HAS_COMPAT_FEATURE(dir->i_sb,   EXT4_FEATURE_COMPAT_DIR_INDEX) &&   (EXT4_I(dir)->i_flags & EXT4_INDEX_FL))
+#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX)
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+
+#define DX_HASH_LEGACY 0
+#define DX_HASH_HALF_MD4 1
+#define DX_HASH_TEA 2
+#define DX_HASH_LEGACY_UNSIGNED 3
+#define DX_HASH_HALF_MD4_UNSIGNED 4
+#define DX_HASH_TEA_UNSIGNED 5
+
+#endif
+
diff --git a/distrib/ext4_utils/src/ext4_extents.h b/distrib/ext4_utils/src/ext4_extents.h
new file mode 100644
index 0000000..b1290f4
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_extents.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _EXT4_EXTENTS
+#define _EXT4_EXTENTS
+
+#include "ext4.h"
+
+#define AGGRESSIVE_TEST_
+
+#define EXTENTS_STATS__
+
+#define CHECK_BINSEARCH__
+
+#define EXT_DEBUG__
+#ifdef EXT_DEBUG
+#define ext_debug(a...) printk(a)
+#else
+#define ext_debug(a...)
+#endif
+
+#define EXT_STATS_
+
+struct ext4_extent {
+ __le32 ee_block;
+ __le16 ee_len;
+ __le16 ee_start_hi;
+ __le32 ee_start_lo;
+};
+
+struct ext4_extent_idx {
+ __le32 ei_block;
+ __le32 ei_leaf_lo;
+ __le16 ei_leaf_hi;
+ __u16 ei_unused;
+};
+
+struct ext4_extent_header {
+ __le16 eh_magic;
+ __le16 eh_entries;
+ __le16 eh_max;
+ __le16 eh_depth;
+ __le32 eh_generation;
+};
+
+#define EXT4_EXT_MAGIC 0xf30a
+
+struct ext4_ext_path {
+ ext4_fsblk_t p_block;
+ __u16 p_depth;
+ struct ext4_extent *p_ext;
+ struct ext4_extent_idx *p_idx;
+ struct ext4_extent_header *p_hdr;
+ struct buffer_head *p_bh;
+};
+
+#define EXT4_EXT_CACHE_NO 0
+#define EXT4_EXT_CACHE_GAP 1
+#define EXT4_EXT_CACHE_EXTENT 2
+
+#define EXT_CONTINUE 0
+#define EXT_BREAK 1
+#define EXT_REPEAT 2
+
+#define EXT_MAX_BLOCK 0xffffffff
+
+#define EXT_INIT_MAX_LEN (1UL << 15)
+#define EXT_UNINIT_MAX_LEN (EXT_INIT_MAX_LEN - 1)
+
+#define EXT_FIRST_EXTENT(__hdr__)   ((struct ext4_extent *) (((char *) (__hdr__)) +   sizeof(struct ext4_extent_header)))
+#define EXT_FIRST_INDEX(__hdr__)   ((struct ext4_extent_idx *) (((char *) (__hdr__)) +   sizeof(struct ext4_extent_header)))
+#define EXT_HAS_FREE_INDEX(__path__)   (le16_to_cpu((__path__)->p_hdr->eh_entries)   < le16_to_cpu((__path__)->p_hdr->eh_max))
+#define EXT_LAST_EXTENT(__hdr__)   (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
+#define EXT_LAST_INDEX(__hdr__)   (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1)
+#define EXT_MAX_EXTENT(__hdr__)   (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+#define EXT_MAX_INDEX(__hdr__)   (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1)
+
+#endif
+
+
diff --git a/distrib/ext4_utils/src/ext4_kernel_headers.h b/distrib/ext4_utils/src/ext4_kernel_headers.h
new file mode 100644
index 0000000..4b24dce
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_kernel_headers.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _EXT4_UTILS_EXT4_KERNEL_HEADERS_H_
+#define _EXT4_UTILS_EXT4_KERNEL_HEADERS_H_
+
+#include <stdint.h>
+
+#ifdef __BIONIC__
+#include <sys/types.h>
+#else
+#define __le64 uint64_t
+#define __le32 uint32_t
+#define __le16 uint16_t
+
+#define __be64 uint64_t
+#define __be32 uint32_t
+#define __be16 uint16_t
+
+#define __u64 uint64_t
+#define __u32 uint32_t
+#define __u16 uint16_t
+#define __u8 uint8_t
+#endif
+
+#include "ext4.h"
+#include "xattr.h"
+#include "ext4_extents.h"
+#include "jbd2.h"
+
+#ifndef __BIONIC__
+#undef __le64
+#undef __le32
+#undef __le16
+
+#undef __be64
+#undef __be32
+#undef __be16
+
+#undef __u64
+#undef __u32
+#undef __u16
+#undef __u8
+#endif
+
+#endif
diff --git a/distrib/ext4_utils/src/ext4_sb.c b/distrib/ext4_utils/src/ext4_sb.c
new file mode 100644
index 0000000..1d527a1
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_sb.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 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 <errno.h>
+
+#include "ext4_sb.h"
+
+int ext4_parse_sb(struct ext4_super_block *sb, struct fs_info *info)
+{
+	uint64_t len_blocks;
+
+        if (sb->s_magic != EXT4_SUPER_MAGIC)
+                return -EINVAL;
+
+        if ((sb->s_state & EXT4_VALID_FS) != EXT4_VALID_FS)
+                return -EINVAL;
+
+	info->block_size = 1024 << sb->s_log_block_size;
+	info->blocks_per_group = sb->s_blocks_per_group;
+	info->inodes_per_group = sb->s_inodes_per_group;
+	info->inode_size = sb->s_inode_size;
+	info->inodes = sb->s_inodes_count;
+	info->feat_ro_compat = sb->s_feature_ro_compat;
+	info->feat_compat = sb->s_feature_compat;
+	info->feat_incompat = sb->s_feature_incompat;
+	info->bg_desc_reserve_blocks = sb->s_reserved_gdt_blocks;
+	info->label = sb->s_volume_name;
+
+	len_blocks = ((uint64_t)sb->s_blocks_count_hi << 32) +
+                sb->s_blocks_count_lo;
+	info->len = (uint64_t)info->block_size * len_blocks;
+
+	return 0;
+}
diff --git a/distrib/ext4_utils/src/ext4_sb.h b/distrib/ext4_utils/src/ext4_sb.h
new file mode 100644
index 0000000..832fa33
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_sb.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#ifndef _EXT4_UTILS_EXT4_SB_H_
+#define _EXT4_UTILS_EXT4_SB_H_
+
+#include "ext4_kernel_headers.h"
+
+#define EXT4_SUPER_MAGIC 0xEF53
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct fs_info {
+	int64_t len;	/* If set to 0, ask the block device for the size,
+			 * if less than 0, reserve that much space at the
+			 * end of the partition, else use the size given. */
+	uint32_t block_size;
+	uint32_t blocks_per_group;
+	uint32_t inodes_per_group;
+	uint32_t inode_size;
+	uint32_t inodes;
+	uint32_t journal_blocks;
+	uint16_t feat_ro_compat;
+	uint16_t feat_compat;
+	uint16_t feat_incompat;
+	uint32_t bg_desc_reserve_blocks;
+	const char *label;
+	uint8_t no_journal;
+};
+
+int ext4_parse_sb(struct ext4_super_block *sb, struct fs_info *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/distrib/ext4_utils/src/ext4_utils.c b/distrib/ext4_utils/src/ext4_utils.c
new file mode 100644
index 0000000..bb6c863
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_utils.c
@@ -0,0 +1,451 @@
+/*
+ * Copyright (C) 2010 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 "ext4_utils.h"
+#include "uuid.h"
+#include "allocate.h"
+#include "indirect.h"
+#include "extent.h"
+
+#include <sparse/sparse.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifdef USE_MINGW
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#endif
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#elif defined(__APPLE__) && defined(__MACH__)
+#include <sys/disk.h>
+#endif
+
+int force = 0;
+struct fs_info info;
+struct fs_aux_info aux_info;
+struct sparse_file *ext4_sparse_file;
+
+jmp_buf setjmp_env;
+
+/* returns 1 if a is a power of b */
+static int is_power_of(int a, int b)
+{
+	while (a > b) {
+		if (a % b)
+			return 0;
+		a /= b;
+	}
+
+	return (a == b) ? 1 : 0;
+}
+
+/* Returns 1 if the bg contains a backup superblock.  On filesystems with
+   the sparse_super feature, only block groups 0, 1, and powers of 3, 5,
+   and 7 have backup superblocks.  Otherwise, all block groups have backup
+   superblocks */
+int ext4_bg_has_super_block(int bg)
+{
+	/* Without sparse_super, every block group has a superblock */
+	if (!(info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER))
+		return 1;
+
+	if (bg == 0 || bg == 1)
+		return 1;
+
+	if (is_power_of(bg, 3) || is_power_of(bg, 5) || is_power_of(bg, 7))
+		return 1;
+
+	return 0;
+}
+
+/* Write the filesystem image to a file */
+void write_ext4_image(int fd, int gz, int sparse, int crc)
+{
+	sparse_file_write(ext4_sparse_file, fd, gz, sparse, crc);
+}
+
+/* Compute the rest of the parameters of the filesystem from the basic info */
+void ext4_create_fs_aux_info()
+{
+	aux_info.first_data_block = (info.block_size > 1024) ? 0 : 1;
+	aux_info.len_blocks = info.len / info.block_size;
+	aux_info.inode_table_blocks = DIV_ROUND_UP(info.inodes_per_group * info.inode_size,
+		info.block_size);
+	aux_info.groups = DIV_ROUND_UP(aux_info.len_blocks - aux_info.first_data_block,
+		info.blocks_per_group);
+	aux_info.blocks_per_ind = info.block_size / sizeof(u32);
+	aux_info.blocks_per_dind = aux_info.blocks_per_ind * aux_info.blocks_per_ind;
+	aux_info.blocks_per_tind = aux_info.blocks_per_dind * aux_info.blocks_per_dind;
+
+	aux_info.bg_desc_blocks =
+		DIV_ROUND_UP(aux_info.groups * sizeof(struct ext2_group_desc),
+			info.block_size);
+
+	aux_info.default_i_flags = EXT4_NOATIME_FL;
+
+	u32 last_group_size = aux_info.len_blocks % info.blocks_per_group;
+	u32 last_header_size = 2 + aux_info.inode_table_blocks;
+	if (ext4_bg_has_super_block(aux_info.groups - 1))
+		last_header_size += 1 + aux_info.bg_desc_blocks +
+			info.bg_desc_reserve_blocks;
+	if (last_group_size > 0 && last_group_size < last_header_size) {
+		aux_info.groups--;
+		aux_info.len_blocks -= last_group_size;
+	}
+
+	aux_info.sb = calloc(info.block_size, 1);
+	/* Alloc an array to hold the pointers to the backup superblocks */
+	aux_info.backup_sb = calloc(aux_info.groups, sizeof(char *));
+
+	if (!aux_info.sb)
+		critical_error_errno("calloc");
+
+	aux_info.bg_desc = calloc(info.block_size, aux_info.bg_desc_blocks);
+	if (!aux_info.bg_desc)
+		critical_error_errno("calloc");
+	aux_info.xattrs = NULL;
+}
+
+void ext4_free_fs_aux_info()
+{
+	unsigned int i;
+
+	for (i=0; i<aux_info.groups; i++) {
+		if (aux_info.backup_sb[i])
+			free(aux_info.backup_sb[i]);
+	}
+	free(aux_info.sb);
+	free(aux_info.bg_desc);
+}
+
+/* Fill in the superblock memory buffer based on the filesystem parameters */
+void ext4_fill_in_sb()
+{
+	unsigned int i;
+	struct ext4_super_block *sb = aux_info.sb;
+
+	sb->s_inodes_count = info.inodes_per_group * aux_info.groups;
+	sb->s_blocks_count_lo = aux_info.len_blocks;
+	sb->s_r_blocks_count_lo = 0;
+	sb->s_free_blocks_count_lo = 0;
+	sb->s_free_inodes_count = 0;
+	sb->s_first_data_block = aux_info.first_data_block;
+	sb->s_log_block_size = log_2(info.block_size / 1024);
+	sb->s_obso_log_frag_size = log_2(info.block_size / 1024);
+	sb->s_blocks_per_group = info.blocks_per_group;
+	sb->s_obso_frags_per_group = info.blocks_per_group;
+	sb->s_inodes_per_group = info.inodes_per_group;
+	sb->s_mtime = 0;
+	sb->s_wtime = 0;
+	sb->s_mnt_count = 0;
+	sb->s_max_mnt_count = 0xFFFF;
+	sb->s_magic = EXT4_SUPER_MAGIC;
+	sb->s_state = EXT4_VALID_FS;
+	sb->s_errors = EXT4_ERRORS_RO;
+	sb->s_minor_rev_level = 0;
+	sb->s_lastcheck = 0;
+	sb->s_checkinterval = 0;
+	sb->s_creator_os = EXT4_OS_LINUX;
+	sb->s_rev_level = EXT4_DYNAMIC_REV;
+	sb->s_def_resuid = EXT4_DEF_RESUID;
+	sb->s_def_resgid = EXT4_DEF_RESGID;
+
+	sb->s_first_ino = EXT4_GOOD_OLD_FIRST_INO;
+	sb->s_inode_size = info.inode_size;
+	sb->s_block_group_nr = 0;
+	sb->s_feature_compat = info.feat_compat;
+	sb->s_feature_incompat = info.feat_incompat;
+	sb->s_feature_ro_compat = info.feat_ro_compat;
+	generate_uuid("extandroid/make_ext4fs", info.label, sb->s_uuid);
+	memset(sb->s_volume_name, 0, sizeof(sb->s_volume_name));
+	strncpy(sb->s_volume_name, info.label, sizeof(sb->s_volume_name));
+	memset(sb->s_last_mounted, 0, sizeof(sb->s_last_mounted));
+	sb->s_algorithm_usage_bitmap = 0;
+
+	sb->s_reserved_gdt_blocks = info.bg_desc_reserve_blocks;
+	sb->s_prealloc_blocks = 0;
+	sb->s_prealloc_dir_blocks = 0;
+
+	//memcpy(sb->s_journal_uuid, sb->s_uuid, sizeof(sb->s_journal_uuid));
+	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
+		sb->s_journal_inum = EXT4_JOURNAL_INO;
+	sb->s_journal_dev = 0;
+	sb->s_last_orphan = 0;
+	sb->s_hash_seed[0] = 0; /* FIXME */
+	sb->s_def_hash_version = DX_HASH_TEA;
+	sb->s_reserved_char_pad = EXT4_JNL_BACKUP_BLOCKS;
+	sb->s_desc_size = sizeof(struct ext2_group_desc);
+	sb->s_default_mount_opts = 0; /* FIXME */
+	sb->s_first_meta_bg = 0;
+	sb->s_mkfs_time = 0;
+	//sb->s_jnl_blocks[17]; /* FIXME */
+
+	sb->s_blocks_count_hi = aux_info.len_blocks >> 32;
+	sb->s_r_blocks_count_hi = 0;
+	sb->s_free_blocks_count_hi = 0;
+	sb->s_min_extra_isize = sizeof(struct ext4_inode) -
+		EXT4_GOOD_OLD_INODE_SIZE;
+	sb->s_want_extra_isize = sizeof(struct ext4_inode) -
+		EXT4_GOOD_OLD_INODE_SIZE;
+	sb->s_flags = 2;
+	sb->s_raid_stride = 0;
+	sb->s_mmp_interval = 0;
+	sb->s_mmp_block = 0;
+	sb->s_raid_stripe_width = 0;
+	sb->s_log_groups_per_flex = 0;
+	sb->s_kbytes_written = 0;
+
+	for (i = 0; i < aux_info.groups; i++) {
+		u64 group_start_block = aux_info.first_data_block + i *
+			info.blocks_per_group;
+		u32 header_size = 0;
+		if (ext4_bg_has_super_block(i)) {
+			if (i != 0) {
+				aux_info.backup_sb[i] = calloc(info.block_size, 1);
+				memcpy(aux_info.backup_sb[i], sb, info.block_size);
+				/* Update the block group nr of this backup superblock */
+				aux_info.backup_sb[i]->s_block_group_nr = i;
+				sparse_file_add_data(ext4_sparse_file, aux_info.backup_sb[i],
+						info.block_size, group_start_block);
+			}
+			sparse_file_add_data(ext4_sparse_file, aux_info.bg_desc,
+				aux_info.bg_desc_blocks * info.block_size,
+				group_start_block + 1);
+			header_size = 1 + aux_info.bg_desc_blocks + info.bg_desc_reserve_blocks;
+		}
+
+		aux_info.bg_desc[i].bg_block_bitmap = group_start_block + header_size;
+		aux_info.bg_desc[i].bg_inode_bitmap = group_start_block + header_size + 1;
+		aux_info.bg_desc[i].bg_inode_table = group_start_block + header_size + 2;
+
+		aux_info.bg_desc[i].bg_free_blocks_count = sb->s_blocks_per_group;
+		aux_info.bg_desc[i].bg_free_inodes_count = sb->s_inodes_per_group;
+		aux_info.bg_desc[i].bg_used_dirs_count = 0;
+	}
+}
+
+void ext4_queue_sb(void)
+{
+	/* The write_data* functions expect only block aligned calls.
+	 * This is not an issue, except when we write out the super
+	 * block on a system with a block size > 1K.  So, we need to
+	 * deal with that here.
+	 */
+	if (info.block_size > 1024) {
+		u8 *buf = calloc(info.block_size, 1);
+		memcpy(buf + 1024, (u8*)aux_info.sb, 1024);
+		sparse_file_add_data(ext4_sparse_file, buf, info.block_size, 0);
+	} else {
+		sparse_file_add_data(ext4_sparse_file, aux_info.sb, 1024, 1);
+	}
+}
+
+void ext4_parse_sb_info(struct ext4_super_block *sb)
+{
+	if (sb->s_magic != EXT4_SUPER_MAGIC)
+		error("superblock magic incorrect");
+
+	if ((sb->s_state & EXT4_VALID_FS) != EXT4_VALID_FS)
+		error("filesystem state not valid");
+
+	ext4_parse_sb(sb, &info);
+
+	ext4_create_fs_aux_info();
+
+	memcpy(aux_info.sb, sb, sizeof(*sb));
+
+	if (aux_info.first_data_block != sb->s_first_data_block)
+		critical_error("first data block does not match");
+}
+
+void ext4_create_resize_inode()
+{
+	struct block_allocation *reserve_inode_alloc = create_allocation();
+	u32 reserve_inode_len = 0;
+	unsigned int i;
+
+	struct ext4_inode *inode = get_inode(EXT4_RESIZE_INO);
+	if (inode == NULL) {
+		error("failed to get resize inode");
+		return;
+	}
+
+	for (i = 0; i < aux_info.groups; i++) {
+		if (ext4_bg_has_super_block(i)) {
+			u64 group_start_block = aux_info.first_data_block + i *
+				info.blocks_per_group;
+			u32 reserved_block_start = group_start_block + 1 +
+				aux_info.bg_desc_blocks;
+			u32 reserved_block_len = info.bg_desc_reserve_blocks;
+			append_region(reserve_inode_alloc, reserved_block_start,
+				reserved_block_len, i);
+			reserve_inode_len += reserved_block_len;
+		}
+	}
+
+	inode_attach_resize(inode, reserve_inode_alloc);
+
+	inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+	inode->i_links_count = 1;
+
+	free_alloc(reserve_inode_alloc);
+}
+
+/* Allocate the blocks to hold a journal inode and connect them to the
+   reserved journal inode */
+void ext4_create_journal_inode()
+{
+	struct ext4_inode *inode = get_inode(EXT4_JOURNAL_INO);
+	if (inode == NULL) {
+		error("failed to get journal inode");
+		return;
+	}
+
+	u8 *journal_data = inode_allocate_data_extents(inode,
+			info.journal_blocks * info.block_size,
+			info.journal_blocks * info.block_size);
+	if (!journal_data) {
+		error("failed to allocate extents for journal data");
+		return;
+	}
+
+	inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR;
+	inode->i_links_count = 1;
+
+	journal_superblock_t *jsb = (journal_superblock_t *)journal_data;
+	jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER);
+	jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2);
+	jsb->s_blocksize = htonl(info.block_size);
+	jsb->s_maxlen = htonl(info.journal_blocks);
+	jsb->s_nr_users = htonl(1);
+	jsb->s_first = htonl(1);
+	jsb->s_sequence = htonl(1);
+
+	memcpy(aux_info.sb->s_jnl_blocks, &inode->i_block, sizeof(inode->i_block));
+}
+
+/* Update the number of free blocks and inodes in the filesystem and in each
+   block group */
+void ext4_update_free()
+{
+	u32 i;
+
+	for (i = 0; i < aux_info.groups; i++) {
+		u32 bg_free_blocks = get_free_blocks(i);
+		u32 bg_free_inodes = get_free_inodes(i);
+		u16 crc;
+
+		aux_info.bg_desc[i].bg_free_blocks_count = bg_free_blocks;
+		aux_info.sb->s_free_blocks_count_lo += bg_free_blocks;
+
+		aux_info.bg_desc[i].bg_free_inodes_count = bg_free_inodes;
+		aux_info.sb->s_free_inodes_count += bg_free_inodes;
+
+		aux_info.bg_desc[i].bg_used_dirs_count += get_directories(i);
+
+		aux_info.bg_desc[i].bg_flags = get_bg_flags(i);
+
+		crc = ext4_crc16(~0, aux_info.sb->s_uuid, sizeof(aux_info.sb->s_uuid));
+		crc = ext4_crc16(crc, &i, sizeof(i));
+		crc = ext4_crc16(crc, &aux_info.bg_desc[i], offsetof(struct ext2_group_desc, bg_checksum));
+		aux_info.bg_desc[i].bg_checksum = crc;
+	}
+}
+
+u64 get_block_device_size(int fd)
+{
+	u64 size = 0;
+	int ret;
+
+#if defined(__linux__)
+	ret = ioctl(fd, BLKGETSIZE64, &size);
+#elif defined(__APPLE__) && defined(__MACH__)
+	ret = ioctl(fd, DKIOCGETBLOCKCOUNT, &size);
+#else
+	close(fd);
+	return 0;
+#endif
+
+	if (ret)
+		return 0;
+
+	return size;
+}
+
+int is_block_device_fd(int fd)
+{
+#ifdef USE_MINGW
+	return 0;
+#else
+	struct stat st;
+	int ret = fstat(fd, &st);
+	if (ret < 0)
+		return 0;
+
+	return S_ISBLK(st.st_mode);
+#endif
+}
+
+u64 get_file_size(int fd)
+{
+	struct stat buf;
+	int ret;
+	u64 reserve_len = 0;
+	s64 computed_size;
+
+	ret = fstat(fd, &buf);
+	if (ret)
+		return 0;
+
+	if (info.len < 0)
+		reserve_len = -info.len;
+
+	if (S_ISREG(buf.st_mode))
+		computed_size = buf.st_size - reserve_len;
+	else if (S_ISBLK(buf.st_mode))
+		computed_size = get_block_device_size(fd) - reserve_len;
+	else
+		computed_size = 0;
+
+	if (computed_size < 0) {
+		warn("Computed filesystem size less than 0");
+		computed_size = 0;
+	}
+
+	return computed_size;
+}
+
+u64 parse_num(const char *arg)
+{
+	char *endptr;
+	u64 num = strtoull(arg, &endptr, 10);
+	if (*endptr == 'k' || *endptr == 'K')
+		num *= 1024LL;
+	else if (*endptr == 'm' || *endptr == 'M')
+		num *= 1024LL * 1024LL;
+	else if (*endptr == 'g' || *endptr == 'G')
+		num *= 1024LL * 1024LL * 1024LL;
+
+	return num;
+}
diff --git a/distrib/ext4_utils/src/ext4_utils.h b/distrib/ext4_utils/src/ext4_utils.h
new file mode 100644
index 0000000..c6f52b5
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4_utils.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _EXT4_UTILS_H_
+#define _EXT4_UTILS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <setjmp.h>
+#include <stdint.h>
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define ftruncate64 ftruncate
+#define mmap64 mmap
+#define off64_t off_t
+#endif
+
+#include "ext4_sb.h"
+
+extern int force;
+
+#define warn(fmt, args...) do { fprintf(stderr, "warning: %s: " fmt "\n", __func__, ## args); } while (0)
+#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); if (!force) longjmp(setjmp_env, EXIT_FAILURE); } while (0)
+#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
+#define critical_error(fmt, args...) do { fprintf(stderr, "critical error: %s: " fmt "\n", __func__, ## args); longjmp(setjmp_env, EXIT_FAILURE); } while (0)
+#define critical_error_errno(s, args...) critical_error(s ": %s", ##args, strerror(errno))
+
+#define EXT4_JNL_BACKUP_BLOCKS 1
+
+#ifndef min /* already defined by windows.h */
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+
+/* XXX */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+#define le32_to_cpu(x) (x)
+#define le16_to_cpu(x) (x)
+
+#ifdef __LP64__
+typedef unsigned long u64;
+typedef signed long s64;
+#else
+typedef unsigned long long u64;
+typedef signed long long s64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short int u16;
+typedef unsigned char u8;
+
+struct block_group_info;
+struct xattr_list_element;
+
+struct ext2_group_desc {
+	u32 bg_block_bitmap;
+	u32 bg_inode_bitmap;
+	u32 bg_inode_table;
+	u16 bg_free_blocks_count;
+	u16 bg_free_inodes_count;
+	u16 bg_used_dirs_count;
+	u16 bg_flags;
+	u32 bg_reserved[2];
+	u16 bg_reserved16;
+	u16 bg_checksum;
+};
+
+struct fs_aux_info {
+	struct ext4_super_block *sb;
+	struct ext4_super_block **backup_sb;
+	struct ext2_group_desc *bg_desc;
+	struct block_group_info *bgs;
+	struct xattr_list_element *xattrs;
+	u32 first_data_block;
+	u64 len_blocks;
+	u32 inode_table_blocks;
+	u32 groups;
+	u32 bg_desc_blocks;
+	u32 default_i_flags;
+	u32 blocks_per_ind;
+	u32 blocks_per_dind;
+	u32 blocks_per_tind;
+};
+
+extern struct fs_info info;
+extern struct fs_aux_info aux_info;
+extern struct sparse_file *ext4_sparse_file;
+
+extern jmp_buf setjmp_env;
+
+static inline int log_2(int j)
+{
+	int i;
+
+	for (i = 0; j > 0; i++)
+		j >>= 1;
+
+	return i - 1;
+}
+
+int ext4_bg_has_super_block(int bg);
+void write_ext4_image(int fd, int gz, int sparse, int crc);
+void ext4_create_fs_aux_info(void);
+void ext4_free_fs_aux_info(void);
+void ext4_fill_in_sb(void);
+void ext4_create_resize_inode(void);
+void ext4_create_journal_inode(void);
+void ext4_update_free(void);
+void ext4_queue_sb(void);
+u64 get_block_device_size(int fd);
+int is_block_device_fd(int fd);
+u64 get_file_size(int fd);
+u64 parse_num(const char *arg);
+void ext4_parse_sb_info(struct ext4_super_block *sb);
+u16 ext4_crc16(u16 crc_in, const void *buf, int size);
+
+typedef void (*fs_config_func_t)(const char *path, int dir, unsigned *uid, unsigned *gid,
+        unsigned *mode, uint64_t *capabilities);
+
+struct selabel_handle;
+
+int make_ext4fs_internal(int fd, const char *directory,
+                         const char *mountpoint, fs_config_func_t fs_config_func, int gzip,
+                         int sparse, int crc, int wipe,
+                         struct selabel_handle *sehnd, int verbose);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/distrib/ext4_utils/src/ext4fixup.c b/distrib/ext4_utils/src/ext4fixup.c
new file mode 100644
index 0000000..7beeefb
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4fixup.c
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2010 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 "ext4_utils.h"
+#include "make_ext4fs.h"
+#include "ext4_extents.h"
+#include "allocate.h"
+#include "ext4fixup.h"
+
+#include <sparse/sparse.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#ifndef USE_MINGW
+#include <sys/mman.h>
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+/* The inode block count for a file/directory is in units of 512 byte blocks,
+ * _NOT_ the filesystem block size!
+ */
+#define INODE_BLOCK_SIZE 512
+
+#define MAX_EXT4_BLOCK_SIZE 4096
+
+/* The two modes the recurse_dir() can be in */
+#define SANITY_CHECK_PASS 1
+#define MARK_INODE_NUMS   2
+#define UPDATE_INODE_NUMS 3
+
+/* Magic numbers to indicate what state the update process is in */
+#define MAGIC_STATE_MARKING_INUMS  0x7000151515565512ll
+#define MAGIC_STATE_UPDATING_INUMS 0x6121131211735123ll
+#define MAGIC_STATE_UPDATING_SB    0x15e1715151558477ll
+
+/* Internal state variables corresponding to the magic numbers */
+#define STATE_UNSET          0
+#define STATE_MARKING_INUMS  1
+#define STATE_UPDATING_INUMS 2
+#define STATE_UPDATING_SB    3
+
+/* Used for automated testing of this programs ability to stop and be restarted wthout error */
+static int bail_phase = 0;
+static int bail_loc = 0;
+static int bail_count = 0;
+static int count = 0;
+
+/* global flags */
+static int verbose = 0;
+static int no_write = 0;
+
+static int new_inodes_per_group = 0;
+
+static int no_write_fixup_state = 0;
+
+static int compute_new_inum(unsigned int old_inum)
+{
+    unsigned int group, offset;
+
+    group = (old_inum - 1) / info.inodes_per_group;
+    offset = (old_inum -1) % info.inodes_per_group;
+
+    return (group * new_inodes_per_group) + offset + 1;
+}
+
+/* Function to read the primary superblock */
+static void read_sb(int fd, struct ext4_super_block *sb)
+{
+    off64_t ret;
+
+    ret = lseek64(fd, 1024, SEEK_SET);
+    if (ret < 0)
+        critical_error_errno("failed to seek to superblock");
+
+    ret = read(fd, sb, sizeof(*sb));
+    if (ret < 0)
+        critical_error_errno("failed to read superblock");
+    if (ret != sizeof(*sb))
+        critical_error("failed to read all of superblock");
+}
+
+/* Function to write a primary or backup superblock at a given offset */
+static void write_sb(int fd, unsigned long long offset, struct ext4_super_block *sb)
+{
+    off64_t ret;
+
+    if (no_write) {
+        return;
+    }
+
+    ret = lseek64(fd, offset, SEEK_SET);
+    if (ret < 0)
+        critical_error_errno("failed to seek to superblock");
+
+    ret = write(fd, sb, sizeof(*sb));
+    if (ret < 0)
+        critical_error_errno("failed to write superblock");
+    if (ret != sizeof(*sb))
+        critical_error("failed to write all of superblock");
+}
+
+static int get_fs_fixup_state(int fd)
+{
+    unsigned long long magic;
+    int ret, len;
+
+    if (no_write) {
+        return no_write_fixup_state;
+    }
+
+    lseek64(fd, 0, SEEK_SET);
+    len = read(fd, &magic, sizeof(magic));
+    if (len != sizeof(magic)) {
+        critical_error("cannot read fixup_state\n");
+    }
+
+    switch (magic) {
+        case MAGIC_STATE_MARKING_INUMS:
+            ret = STATE_MARKING_INUMS;
+            break;
+        case MAGIC_STATE_UPDATING_INUMS:
+            ret = STATE_UPDATING_INUMS;
+            break;
+        case MAGIC_STATE_UPDATING_SB:
+            ret = STATE_UPDATING_SB;
+            break;
+        default:
+            ret = STATE_UNSET;
+    }
+    return ret;
+}
+
+static int set_fs_fixup_state(int fd, int state)
+{
+    unsigned long long magic;
+    struct ext4_super_block sb;
+    int len;
+
+    if (no_write) {
+        no_write_fixup_state = state;
+        return 0;
+    }
+
+    switch (state) {
+        case STATE_MARKING_INUMS:
+            magic = MAGIC_STATE_MARKING_INUMS;
+            break;
+        case STATE_UPDATING_INUMS:
+            magic = MAGIC_STATE_UPDATING_INUMS;
+            break;
+        case STATE_UPDATING_SB:
+            magic = MAGIC_STATE_UPDATING_SB;
+            break;
+        case STATE_UNSET:
+        default:
+            magic = 0ll;
+            break;
+    }
+
+    lseek64(fd, 0, SEEK_SET);
+    len = write(fd, &magic, sizeof(magic));
+    if (len != sizeof(magic)) {
+        critical_error("cannot write fixup_state\n");
+    }
+
+    read_sb(fd, &sb);
+    if (magic) {
+        /* If we are in the process of updating the filesystem, make it unmountable */
+        sb.s_desc_size |= 1;
+    } else {
+        /* we are done, so make the filesystem mountable again */
+        sb.s_desc_size &= ~1;
+    }
+    write_sb(fd, 1024, &sb);
+
+    return 0;
+}
+
+static int read_ext(int fd)
+{
+    off64_t ret;
+    struct ext4_super_block sb;
+
+    read_sb(fd, &sb);
+
+    ext4_parse_sb_info(&sb);
+
+    if (info.feat_incompat & EXT4_FEATURE_INCOMPAT_RECOVER) {
+        critical_error("Filesystem needs recovery first, mount and unmount to do that\n");
+    }
+
+    /* Clear the low bit which is set while this tool is in progress.
+     * If the tool crashes, it will still be set when we restart.
+     * The low bit is set to make the filesystem unmountable while
+     * it is being fixed up.  Also allow 0, which means the old ext2
+     * size is in use.
+     */
+    if (((sb.s_desc_size & ~1) != sizeof(struct ext2_group_desc)) &&
+        ((sb.s_desc_size & ~1) != 0))
+        critical_error("error: bg_desc_size != sizeof(struct ext2_group_desc)\n");
+
+    ret = lseek64(fd, info.len, SEEK_SET);
+    if (ret < 0)
+        critical_error_errno("failed to seek to end of input image");
+
+    ret = lseek64(fd, info.block_size * (aux_info.first_data_block + 1), SEEK_SET);
+    if (ret < 0)
+        critical_error_errno("failed to seek to block group descriptors");
+
+    ret = read(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
+    if (ret < 0)
+        critical_error_errno("failed to read block group descriptors");
+    if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
+        critical_error("failed to read all of block group descriptors");
+
+    if (verbose) {
+        printf("Found filesystem with parameters:\n");
+        printf("    Size: %"PRIu64"\n", info.len);
+        printf("    Block size: %d\n", info.block_size);
+        printf("    Blocks per group: %d\n", info.blocks_per_group);
+        printf("    Inodes per group: %d\n", info.inodes_per_group);
+        printf("    Inode size: %d\n", info.inode_size);
+        printf("    Label: %s\n", info.label);
+        printf("    Blocks: %"PRIu64"\n", aux_info.len_blocks);
+        printf("    Block groups: %d\n", aux_info.groups);
+        printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+        printf("    Used %d/%d inodes and %d/%d blocks\n",
+                aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
+                aux_info.sb->s_inodes_count,
+                aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
+                aux_info.sb->s_blocks_count_lo);
+    }
+
+    return 0;
+}
+
+static int read_inode(int fd, unsigned int inum, struct ext4_inode *inode)
+{
+    unsigned int bg_num, bg_offset;
+    off64_t inode_offset;
+    int len;
+
+    bg_num = (inum-1) / info.inodes_per_group;
+    bg_offset = (inum-1) % info.inodes_per_group;
+
+    inode_offset = ((unsigned long long)aux_info.bg_desc[bg_num].bg_inode_table * info.block_size) +
+                    (bg_offset * info.inode_size);
+
+    if (lseek64(fd, inode_offset, SEEK_SET) < 0) {
+        critical_error_errno("failed to seek to inode %d\n", inum);
+    }
+
+    len=read(fd, inode, sizeof(*inode));
+    if (len != sizeof(*inode)) {
+        critical_error_errno("failed to read inode %d\n", inum);
+    }
+
+    return 0;
+}
+
+static int read_block(int fd, unsigned long long block_num, void *block)
+{
+    off64_t off;
+    unsigned int len;
+
+    off = block_num * info.block_size;
+
+    if (lseek64(fd, off, SEEK_SET) , 0) {
+        critical_error_errno("failed to seek to block %lld\n", block_num);
+    }
+
+    len=read(fd, block, info.block_size);
+    if (len != info.block_size) {
+        critical_error_errno("failed to read block %lld\n", block_num);
+    }
+
+    return 0;
+}
+
+static int write_block(int fd, unsigned long long block_num, void *block)
+{
+    off64_t off;
+    unsigned int len;
+
+    if (no_write) {
+        return 0;
+    }
+
+    off = block_num * info.block_size;
+
+    if (lseek64(fd, off, SEEK_SET) < 0) {
+        critical_error_errno("failed to seek to block %lld\n", block_num);
+    }
+
+    len=write(fd, block, info.block_size);
+    if (len != info.block_size) {
+        critical_error_errno("failed to write block %lld\n", block_num);
+    }
+
+    return 0;
+}
+
+static int bitmap_get_bit(u8 *bitmap, u32 bit)
+{
+        if (bitmap[bit / 8] & (1 << (bit % 8)))
+                return 1;
+
+        return 0;
+}
+
+static void bitmap_clear_bit(u8 *bitmap, u32 bit)
+{
+        bitmap[bit / 8] &= ~(1 << (bit % 8));
+
+        return;
+}
+
+static void check_inode_bitmap(int fd, unsigned int bg_num)
+{
+    unsigned int inode_bitmap_block_num;
+    unsigned char block[MAX_EXT4_BLOCK_SIZE];
+    int i, bitmap_updated = 0;
+
+    /* Using the bg_num, aux_info.bg_desc[], info.inodes_per_group and
+     * new_inodes_per_group, retrieve the inode bitmap, and make sure
+     * the bits between the old and new size are clear
+     */
+    inode_bitmap_block_num = aux_info.bg_desc[bg_num].bg_inode_bitmap;
+
+    read_block(fd, inode_bitmap_block_num, block);
+
+    for (i = info.inodes_per_group; i < new_inodes_per_group; i++) {
+        if (bitmap_get_bit(block, i)) {
+            bitmap_clear_bit(block, i);
+            bitmap_updated = 1;
+        }
+    }
+
+    if (bitmap_updated) {
+        if (verbose) {
+            printf("Warning: updated inode bitmap for block group %d\n", bg_num);
+        }
+        write_block(fd, inode_bitmap_block_num, block);
+    }
+
+    return;
+}
+
+/* Update the superblock and bgdesc of the specified block group */
+static int update_superblocks_and_bg_desc(int fd, int state)
+{
+    off64_t ret;
+    struct ext4_super_block sb;
+    unsigned int num_block_groups, total_new_inodes;
+    unsigned int i;
+
+
+    read_sb(fd, &sb);
+
+    /* Compute how many more inodes are now available */
+    num_block_groups = DIV_ROUND_UP(aux_info.len_blocks, info.blocks_per_group);
+    total_new_inodes = num_block_groups * (new_inodes_per_group - sb.s_inodes_per_group);
+
+    if (verbose) {
+        printf("created %d additional inodes\n", total_new_inodes);
+    }
+
+    /* Update the free inodes count in each block group descriptor */
+    for (i = 0; i < num_block_groups; i++) {
+       if (state == STATE_UPDATING_SB) {
+           aux_info.bg_desc[i].bg_free_inodes_count += (new_inodes_per_group - sb.s_inodes_per_group);
+       }
+       check_inode_bitmap(fd, i);
+    }
+
+    /* First some sanity checks */
+    if ((sb.s_inodes_count + total_new_inodes) != (new_inodes_per_group * num_block_groups)) {
+        critical_error("Failed sanity check on new inode count\n");
+    }
+    if (new_inodes_per_group % (info.block_size/info.inode_size)) {
+        critical_error("Failed sanity check on new inode per group alignment\n");
+    }
+
+    /* Update the free inodes count in the superblock */
+    sb.s_inodes_count += total_new_inodes;
+    sb.s_free_inodes_count += total_new_inodes;
+    sb.s_inodes_per_group = new_inodes_per_group;
+
+    for (i = 0; i < aux_info.groups; i++) {
+        if (ext4_bg_has_super_block(i)) {
+            unsigned int sb_offset;
+
+            if (i == 0) {
+              /* The first superblock is offset by 1K to leave room for boot sectors */
+              sb_offset = 1024;
+            } else {
+              sb_offset = 0;
+            }
+
+            sb.s_block_group_nr = i;
+            /* Don't write out the backup superblocks with the bit set in the s_desc_size
+             * which prevents the filesystem from mounting.  The bit for the primary
+             * superblock will be cleared on the final call to set_fs_fixup_state() */
+            if (i != 0) {
+                sb.s_desc_size &= ~1;
+            }
+
+            write_sb(fd, (unsigned long long)i * info.blocks_per_group * info.block_size + sb_offset, &sb);
+
+            ret = lseek64(fd, ((unsigned long long)i * info.blocks_per_group * info.block_size) +
+                              (info.block_size * (aux_info.first_data_block + 1)), SEEK_SET);
+            if (ret < 0)
+                critical_error_errno("failed to seek to block group descriptors");
+
+            if (!no_write) {
+                ret = write(fd, aux_info.bg_desc, info.block_size * aux_info.bg_desc_blocks);
+                if (ret < 0)
+                    critical_error_errno("failed to write block group descriptors");
+                if (ret != (int)info.block_size * (int)aux_info.bg_desc_blocks)
+                    critical_error("failed to write all of block group descriptors");
+            }
+        }
+        if ((bail_phase == 4) && ((unsigned int)bail_count == i)) {
+            critical_error("bailing at phase 4\n");
+        }
+    }
+
+    return 0;
+}
+
+
+static int get_direct_blocks(struct ext4_inode *inode, unsigned long long *block_list,
+                                                       unsigned int *count)
+{
+    unsigned int i = 0;
+    unsigned int ret = 0;
+    unsigned int sectors_per_block;
+
+    sectors_per_block = info.block_size / INODE_BLOCK_SIZE;
+    while ((i < (inode->i_blocks_lo / sectors_per_block)) && (i < EXT4_NDIR_BLOCKS)) {
+        block_list[i] = inode->i_block[i];
+        i++;
+    }
+
+    *count += i;
+
+    if ((inode->i_blocks_lo / sectors_per_block) > EXT4_NDIR_BLOCKS) {
+        ret = 1;
+    }
+
+    return ret;
+}
+
+static int get_indirect_blocks(int fd, struct ext4_inode *inode,
+                               unsigned long long *block_list, unsigned int *count)
+{
+    unsigned int i;
+    unsigned int *indirect_block;
+    unsigned int sectors_per_block;
+
+    sectors_per_block = info.block_size / INODE_BLOCK_SIZE;
+
+    indirect_block = (unsigned int *)malloc(info.block_size);
+    if (indirect_block == 0) {
+        critical_error("failed to allocate memory for indirect_block\n");
+    }
+
+    read_block(fd, inode->i_block[EXT4_NDIR_BLOCKS], indirect_block);
+
+    for(i = 0; i < (inode->i_blocks_lo / sectors_per_block - EXT4_NDIR_BLOCKS); i++) {
+       block_list[EXT4_NDIR_BLOCKS+i] = indirect_block[i];
+    }
+
+    *count += i;
+
+    free(indirect_block);
+
+    return 0;
+}
+
+static int get_block_list_indirect(int fd, struct ext4_inode *inode, unsigned long long *block_list)
+{
+    unsigned int count=0;
+
+    if (get_direct_blocks(inode, block_list, &count)) {
+        get_indirect_blocks(fd, inode, block_list, &count);
+    }
+
+    return count;
+}
+
+static int get_extent_ents(struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
+{
+    int i, j;
+    struct ext4_extent *extent;
+    off64_t fs_block_num;
+
+    if (ext_hdr->eh_depth != 0) {
+        critical_error("get_extent_ents called with eh_depth != 0\n");
+    }
+
+    /* The extent entries immediately follow the header, so add 1 to the pointer
+     * and cast it to an extent pointer.
+     */
+    extent = (struct ext4_extent *)(ext_hdr + 1);
+
+    for (i = 0; i < ext_hdr->eh_entries; i++) {
+         fs_block_num = ((off64_t)extent->ee_start_hi << 32) | extent->ee_start_lo;
+         for (j = 0; j < extent->ee_len; j++) {
+             block_list[extent->ee_block+j] = fs_block_num+j;
+         }
+         extent++;
+    }
+
+    return 0;
+}
+
+static int get_extent_idx(int fd, struct ext4_extent_header *ext_hdr, unsigned long long *block_list)
+{
+    int i;
+    struct ext4_extent_idx *extent_idx;
+    struct ext4_extent_header *tmp_ext_hdr;
+    off64_t fs_block_num;
+    unsigned char block[MAX_EXT4_BLOCK_SIZE];
+
+    /* Sanity check */
+    if (ext_hdr->eh_depth == 0) {
+        critical_error("get_extent_idx called with eh_depth == 0\n");
+    }
+
+    /* The extent entries immediately follow the header, so add 1 to the pointer
+     * and cast it to an extent pointer.
+     */
+    extent_idx = (struct ext4_extent_idx *)(ext_hdr + 1);
+
+    for (i = 0; i < ext_hdr->eh_entries; i++) {
+         fs_block_num = ((off64_t)extent_idx->ei_leaf_hi << 32) | extent_idx->ei_leaf_lo;
+         read_block(fd, fs_block_num, block);
+         tmp_ext_hdr = (struct ext4_extent_header *)block;
+
+         if (tmp_ext_hdr->eh_depth == 0) {
+             get_extent_ents(tmp_ext_hdr, block_list); /* leaf node, fill in block_list */
+         } else {
+             get_extent_idx(fd, tmp_ext_hdr, block_list); /* recurse down the tree */
+         }
+    }
+
+    return 0;
+}
+
+static int get_block_list_extents(int fd, struct ext4_inode *inode, unsigned long long *block_list)
+{
+    struct ext4_extent_header *extent_hdr;
+
+    extent_hdr = (struct ext4_extent_header *)inode->i_block;
+
+    if (extent_hdr->eh_magic != EXT4_EXT_MAGIC) {
+        critical_error("extent header has unexpected magic value 0x%4.4x\n",
+                       extent_hdr->eh_magic);
+    }
+
+    if (extent_hdr->eh_depth == 0) {
+         get_extent_ents((struct ext4_extent_header *)inode->i_block, block_list);
+         return 0;
+    }
+
+    get_extent_idx(fd, (struct ext4_extent_header *)inode->i_block, block_list);
+
+    return 0;
+}
+
+static int is_entry_dir(int fd, struct ext4_dir_entry_2 *dirp, int pass)
+{
+    struct ext4_inode inode;
+    int ret = 0;
+
+    if (dirp->file_type == EXT4_FT_DIR) {
+        ret = 1;
+    } else if (dirp->file_type == EXT4_FT_UNKNOWN) {
+        /* Somebody was too lazy to fill in the dir entry,
+         * so we have to go fetch it from the inode. Grrr.
+         */
+        /* if UPDATE_INODE_NUMS pass and the inode high bit is not
+         * set return false so we don't recurse down the tree that is
+         * already updated.  Otherwise, fetch inode, and return answer.
+         */
+        if ((pass == UPDATE_INODE_NUMS) && !(dirp->inode & 0x80000000)) {
+            ret = 0;
+        } else {
+            read_inode(fd, (dirp->inode & 0x7fffffff), &inode);
+            if (S_ISDIR(inode.i_mode)) {
+                ret = 1;
+            }
+        }
+    }
+
+    return ret;
+}
+
+static int recurse_dir(int fd, struct ext4_inode *inode, char *dirbuf, int dirsize, int mode)
+{
+    unsigned long long *block_list;
+    unsigned int num_blocks;
+    struct ext4_dir_entry_2 *dirp, *prev_dirp = 0;
+    char name[256];
+    unsigned int i, leftover_space, is_dir;
+    struct ext4_inode tmp_inode;
+    int tmp_dirsize;
+    char *tmp_dirbuf;
+
+    switch (mode) {
+        case SANITY_CHECK_PASS:
+        case MARK_INODE_NUMS:
+        case UPDATE_INODE_NUMS:
+            break;
+        default:
+            critical_error("recurse_dir() called witn unknown mode!\n");
+    }
+
+    if (dirsize % info.block_size) {
+        critical_error("dirsize %d not a multiple of block_size %d.  This is unexpected!\n",
+                dirsize, info.block_size);
+    }
+
+    num_blocks = dirsize / info.block_size;
+
+    block_list = malloc((num_blocks + 1) * sizeof(*block_list));
+    if (block_list == 0) {
+        critical_error("failed to allocate memory for block_list\n");
+    }
+
+    if (inode->i_flags & EXT4_EXTENTS_FL) {
+        get_block_list_extents(fd, inode, block_list);
+    } else {
+        /* A directory that requires doubly or triply indirect blocks in huge indeed,
+         * and will almost certainly not exist, especially since make_ext4fs only creates
+         * directories with extents, and the kernel will too, but check to make sure the
+         * directory is not that big and give an error if so.  Our limit is 12 direct blocks,
+         * plus block_size/4 singly indirect blocks, which for a filesystem with 4K blocks
+         * is a directory 1036 blocks long, or 4,243,456 bytes long!  Assuming an average
+         * filename length of 20 (which I think is generous) thats 20 + 8 bytes overhead
+         * per entry, or 151,552 entries in the directory!
+         */
+        if (num_blocks > (info.block_size / 4 + EXT4_NDIR_BLOCKS)) {
+            critical_error("Non-extent based directory is too big!\n");
+        }
+        get_block_list_indirect(fd, inode, block_list);
+    }
+
+    /* Read in all the blocks for this directory */
+    for (i = 0; i < num_blocks; i++) {
+        read_block(fd, block_list[i], dirbuf + (i * info.block_size));
+    }
+
+    dirp = (struct ext4_dir_entry_2 *)dirbuf;
+    while (dirp < (struct ext4_dir_entry_2 *)(dirbuf + dirsize)) {
+        count++;
+        leftover_space = (char *)(dirbuf + dirsize) - (char *)dirp;
+        if (((mode == SANITY_CHECK_PASS) || (mode == UPDATE_INODE_NUMS)) &&
+            (leftover_space <= 8) && prev_dirp) {
+            /* This is a bug in an older version of make_ext4fs, where it
+             * didn't properly include the rest of the block in rec_len.
+             * Update rec_len on the previous entry to include the rest of
+             * the block and exit the loop.
+             */
+            if (verbose) {
+                printf("fixing up short rec_len for diretory entry for %s\n", name);
+            }
+            prev_dirp->rec_len += leftover_space;
+            break;
+        }
+
+        if (dirp->inode == 0) {
+            /* This is the last entry in the directory */
+            break;
+        }
+
+        strncpy(name, dirp->name, dirp->name_len);
+        name[dirp->name_len]='\0';
+
+        /* Only recurse on pass UPDATE_INODE_NUMS if the high bit is set.
+         * Otherwise, this inode entry has already been updated
+         * and we'll do the wrong thing.  Also don't recurse on . or ..,
+         * and certainly not on non-directories!
+         */
+        /* Hrm, looks like filesystems made by fastboot on stingray set the file_type
+         * flag, but the lost+found directory has the type set to Unknown, which
+         * seems to imply I need to read the inode and get it.
+         */
+        is_dir = is_entry_dir(fd, dirp, mode);
+        if ( is_dir && (strcmp(name, ".") && strcmp(name, "..")) &&
+            ((mode == SANITY_CHECK_PASS) || (mode == MARK_INODE_NUMS) ||
+              ((mode == UPDATE_INODE_NUMS) && (dirp->inode & 0x80000000))) ) {
+            /* A directory!  Recurse! */
+            read_inode(fd, dirp->inode & 0x7fffffff, &tmp_inode);
+
+            if (!S_ISDIR(tmp_inode.i_mode)) {
+                critical_error("inode %d for name %s does not point to a directory\n",
+                        dirp->inode & 0x7fffffff, name);
+            }
+            if (verbose) {
+                printf("inode %d %s use extents\n", dirp->inode & 0x7fffffff,
+                       (tmp_inode.i_flags & EXT4_EXTENTS_FL) ? "does" : "does not");
+            }
+
+            tmp_dirsize = tmp_inode.i_blocks_lo * INODE_BLOCK_SIZE;
+            if (verbose) {
+                printf("dir size = %d bytes\n", tmp_dirsize);
+            }
+
+            tmp_dirbuf = malloc(tmp_dirsize);
+            if (tmp_dirbuf == 0) {
+                critical_error("failed to allocate memory for tmp_dirbuf\n");
+            }
+
+            recurse_dir(fd, &tmp_inode, tmp_dirbuf, tmp_dirsize, mode);
+
+            free(tmp_dirbuf);
+        }
+
+        if (verbose) {
+            if (is_dir) {
+                printf("Directory %s\n", name);
+            } else {
+                printf("Non-directory %s\n", name);
+            }
+        }
+
+        /* Process entry based on current mode.  Either set high bit or change inode number */
+        if (mode == MARK_INODE_NUMS) {
+            dirp->inode |= 0x80000000;
+        } else if (mode == UPDATE_INODE_NUMS) {
+            if (dirp->inode & 0x80000000) {
+                dirp->inode = compute_new_inum(dirp->inode & 0x7fffffff);
+            }
+        }
+
+        if ((bail_phase == mode) && (bail_loc == 1) && (bail_count == count)) {
+            critical_error("Bailing at phase %d, loc 1 and count %d\n", mode, count);
+        }
+
+        /* Point dirp at the next entry */
+        prev_dirp = dirp;
+        dirp = (struct ext4_dir_entry_2*)((char *)dirp + dirp->rec_len);
+    }
+
+    /* Write out all the blocks for this directory */
+    for (i = 0; i < num_blocks; i++) {
+        write_block(fd, block_list[i], dirbuf + (i * info.block_size));
+        if ((bail_phase == mode) && (bail_loc == 2) && (bail_count <= count)) {
+            critical_error("Bailing at phase %d, loc 2 and count %d\n", mode, count);
+        }
+    }
+
+    free(block_list);
+
+    return 0;
+}
+
+int ext4fixup(char *fsdev)
+{
+    return ext4fixup_internal(fsdev, 0, 0, 0, 0, 0);
+}
+
+int ext4fixup_internal(char *fsdev, int v_flag, int n_flag,
+                       int stop_phase, int stop_loc, int stop_count)
+{
+    int fd;
+    struct ext4_inode root_inode;
+    unsigned int dirsize;
+    char *dirbuf;
+
+    if (setjmp(setjmp_env))
+        return EXIT_FAILURE; /* Handle a call to longjmp() */
+
+    verbose = v_flag;
+    no_write = n_flag;
+
+    bail_phase = stop_phase;
+    bail_loc = stop_loc;
+    bail_count = stop_count;
+
+    fd = open(fsdev, O_RDWR);
+
+    if (fd < 0)
+        critical_error_errno("failed to open filesystem image");
+
+    read_ext(fd);
+
+    if ((info.feat_incompat & EXT4_FEATURE_INCOMPAT_FILETYPE) == 0) {
+        critical_error("Expected filesystem to have filetype flag set\n");
+    }
+
+#if 0 // If we have to fix the directory rec_len issue, we can't use this check
+    /* Check to see if the inodes/group is copacetic */
+    if (info.inodes_per_blockgroup % (info.block_size/info.inode_size) == 0) {
+             /* This filesystem has either already been updated, or was
+              * made correctly.
+              */
+             if (verbose) {
+                 printf("%s: filesystem correct, no work to do\n", me);
+             }
+             exit(0);
+    }
+#endif
+
+    /* Compute what the new value of inodes_per_blockgroup will be when we're done */
+    new_inodes_per_group=ALIGN(info.inodes_per_group,(info.block_size/info.inode_size));
+
+    read_inode(fd, EXT4_ROOT_INO, &root_inode);
+
+    if (!S_ISDIR(root_inode.i_mode)) {
+        critical_error("root inode %d does not point to a directory\n", EXT4_ROOT_INO);
+    }
+    if (verbose) {
+        printf("inode %d %s use extents\n", EXT4_ROOT_INO,
+               (root_inode.i_flags & EXT4_EXTENTS_FL) ? "does" : "does not");
+    }
+
+    dirsize = root_inode.i_blocks_lo * INODE_BLOCK_SIZE;
+    if (verbose) {
+        printf("root dir size = %d bytes\n", dirsize);
+    }
+
+    dirbuf = malloc(dirsize);
+    if (dirbuf == 0) {
+        critical_error("failed to allocate memory for dirbuf\n");
+    }
+
+    /* Perform a sanity check pass first, try to catch any errors that will occur
+     * before we actually change anything, so we don't leave a filesystem in a
+     * corrupted, unrecoverable state.  Set no_write, make it quiet, and do a recurse
+     * pass and a update_superblock pass.  Set flags back to requested state when done.
+     * Only perform sanity check if the state is unset.  If the state is _NOT_ unset,
+     * then the tool has already been run and interrupted, and it presumably ran and
+     * passed sanity checked before it got interrupted.  It is _NOT_ safe to run sanity
+     * check if state is unset because it assumes inodes are to be computed using the
+     * old inodes/group, but some inode numbers may be updated to the new number.
+     */
+    if (get_fs_fixup_state(fd) == STATE_UNSET) {
+        verbose = 0;
+        no_write = 1;
+        recurse_dir(fd, &root_inode, dirbuf, dirsize, SANITY_CHECK_PASS);
+        update_superblocks_and_bg_desc(fd, STATE_UNSET);
+        verbose = v_flag;
+        no_write = n_flag;
+
+        set_fs_fixup_state(fd, STATE_MARKING_INUMS);
+    }
+
+    if (get_fs_fixup_state(fd) == STATE_MARKING_INUMS) {
+        count = 0; /* Reset debugging counter */
+        if (!recurse_dir(fd, &root_inode, dirbuf, dirsize, MARK_INODE_NUMS)) {
+            set_fs_fixup_state(fd, STATE_UPDATING_INUMS);
+        }
+    }
+
+    if (get_fs_fixup_state(fd) == STATE_UPDATING_INUMS) {
+        count = 0; /* Reset debugging counter */
+        if (!recurse_dir(fd, &root_inode, dirbuf, dirsize, UPDATE_INODE_NUMS)) {
+            set_fs_fixup_state(fd, STATE_UPDATING_SB);
+        }
+    }
+
+    if (get_fs_fixup_state(fd) == STATE_UPDATING_SB) {
+        /* set the new inodes/blockgroup number,
+         * and sets the state back to 0.
+         */
+        if (!update_superblocks_and_bg_desc(fd, STATE_UPDATING_SB)) {
+            set_fs_fixup_state(fd, STATE_UNSET);
+        }
+    }
+
+    close(fd);
+
+    return 0;
+}
diff --git a/distrib/ext4_utils/src/ext4fixup.h b/distrib/ext4_utils/src/ext4fixup.h
new file mode 100644
index 0000000..6ea2113
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4fixup.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+int ext4fixup(char *fsdev);
+int ext4fixup_internal(char *fsdev, int v_flag, int n_flag,
+                       int stop_phase, int stop_loc, int stop_count);
+
diff --git a/distrib/ext4_utils/src/ext4fixup_main.c b/distrib/ext4_utils/src/ext4fixup_main.c
new file mode 100644
index 0000000..47c7e65
--- /dev/null
+++ b/distrib/ext4_utils/src/ext4fixup_main.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 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 <unistd.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "ext4fixup.h"
+
+static void usage(char *me)
+{
+    fprintf(stderr, "%s: usage: %s [-vn] <image or block device>\n", me, me);
+}
+
+int main(int argc, char **argv)
+{
+    int opt;
+    int verbose = 0;
+    int no_write = 0;
+    char *fsdev;
+    char *me;
+    int stop_phase = 0, stop_loc = 0, stop_count = 0;
+
+    me = basename(argv[0]);
+
+    while ((opt = getopt(argc, argv, "vnd:")) != -1) {
+        switch (opt) {
+        case 'v':
+            verbose = 1;
+            break;
+        case 'n':
+            no_write = 1;
+            break;
+        case 'd':
+            sscanf(optarg, "%d,%d,%d", &stop_phase, &stop_loc, &stop_count);
+            break;
+        }
+    }
+
+    if (optind >= argc) {
+        fprintf(stderr, "expected image or block device after options\n");
+        usage(me);
+        exit(EXIT_FAILURE);
+    }
+
+    fsdev = argv[optind++];
+
+    if (optind < argc) {
+        fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+        usage(me);
+        exit(EXIT_FAILURE);
+    }
+
+    return ext4fixup_internal(fsdev, verbose, no_write, stop_phase, stop_loc, stop_count);
+}
diff --git a/distrib/ext4_utils/src/extent.c b/distrib/ext4_utils/src/extent.c
new file mode 100644
index 0000000..abb30ce
--- /dev/null
+++ b/distrib/ext4_utils/src/extent.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2010 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 "ext4_utils.h"
+#include "extent.h"
+
+#include <sparse/sparse.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/* Creates data buffers for the first backing_len bytes of a block allocation
+   and queues them to be written */
+static u8 *extent_create_backing(struct block_allocation *alloc,
+	u64 backing_len)
+{
+	u8 *data = calloc(backing_len, 1);
+	if (!data)
+		critical_error_errno("calloc");
+
+	u8 *ptr = data;
+	for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
+		u32 region_block;
+		u32 region_len;
+		u32 len;
+		get_region(alloc, &region_block, &region_len);
+
+		len = min(region_len * info.block_size, backing_len);
+
+		sparse_file_add_data(ext4_sparse_file, ptr, len, region_block);
+		ptr += len;
+		backing_len -= len;
+	}
+
+	return data;
+}
+
+/* Queues each chunk of a file to be written to contiguous data block
+   regions */
+static void extent_create_backing_file(struct block_allocation *alloc,
+	u64 backing_len, const char *filename)
+{
+	off64_t offset = 0;
+	for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
+		u32 region_block;
+		u32 region_len;
+		u32 len;
+		get_region(alloc, &region_block, &region_len);
+
+		len = min(region_len * info.block_size, backing_len);
+
+		sparse_file_add_file(ext4_sparse_file, filename, offset, len,
+				region_block);
+		offset += len;
+		backing_len -= len;
+	}
+}
+
+static struct block_allocation *do_inode_allocate_extents(
+	struct ext4_inode *inode, u64 len)
+{
+	u32 block_len = DIV_ROUND_UP(len, info.block_size);
+	struct block_allocation *alloc = allocate_blocks(block_len + 1);
+	u32 extent_block = 0;
+	u32 file_block = 0;
+	struct ext4_extent *extent;
+	u64 blocks;
+
+	if (alloc == NULL) {
+		error("Failed to allocate %d blocks\n", block_len + 1);
+		return NULL;
+	}
+
+	int allocation_len = block_allocation_num_regions(alloc);
+	if (allocation_len <= 3) {
+		reduce_allocation(alloc, 1);
+	} else {
+		reserve_oob_blocks(alloc, 1);
+		extent_block = get_oob_block(alloc, 0);
+	}
+
+	if (!extent_block) {
+		struct ext4_extent_header *hdr =
+			(struct ext4_extent_header *)&inode->i_block[0];
+		hdr->eh_magic = EXT4_EXT_MAGIC;
+		hdr->eh_entries = allocation_len;
+		hdr->eh_max = 3;
+		hdr->eh_generation = 0;
+		hdr->eh_depth = 0;
+
+		extent = (struct ext4_extent *)&inode->i_block[3];
+	} else {
+		struct ext4_extent_header *hdr =
+			(struct ext4_extent_header *)&inode->i_block[0];
+		hdr->eh_magic = EXT4_EXT_MAGIC;
+		hdr->eh_entries = 1;
+		hdr->eh_max = 3;
+		hdr->eh_generation = 0;
+		hdr->eh_depth = 1;
+
+		struct ext4_extent_idx *idx =
+			(struct ext4_extent_idx *)&inode->i_block[3];
+		idx->ei_block = 0;
+		idx->ei_leaf_lo = extent_block;
+		idx->ei_leaf_hi = 0;
+		idx->ei_unused = 0;
+
+		u8 *data = calloc(info.block_size, 1);
+		if (!data)
+			critical_error_errno("calloc");
+
+		sparse_file_add_data(ext4_sparse_file, data, info.block_size,
+				extent_block);
+
+		if (((int)(info.block_size - sizeof(struct ext4_extent_header) /
+				sizeof(struct ext4_extent))) < allocation_len) {
+			error("File size %"PRIu64" is too big to fit in a single extent block\n",
+					len);
+			return NULL;
+		}
+
+		hdr = (struct ext4_extent_header *)data;
+		hdr->eh_magic = EXT4_EXT_MAGIC;
+		hdr->eh_entries = allocation_len;
+		hdr->eh_max = (info.block_size - sizeof(struct ext4_extent_header)) /
+			sizeof(struct ext4_extent);
+		hdr->eh_generation = 0;
+		hdr->eh_depth = 0;
+
+		extent = (struct ext4_extent *)(data +
+			sizeof(struct ext4_extent_header));
+	}
+
+	for (; !last_region(alloc); extent++, get_next_region(alloc)) {
+		u32 region_block;
+		u32 region_len;
+
+		get_region(alloc, &region_block, &region_len);
+		extent->ee_block = file_block;
+		extent->ee_len = region_len;
+		extent->ee_start_hi = 0;
+		extent->ee_start_lo = region_block;
+		file_block += region_len;
+	}
+
+	if (extent_block)
+		block_len += 1;
+
+	blocks = (u64)block_len * info.block_size / 512;
+
+	inode->i_flags |= EXT4_EXTENTS_FL;
+	inode->i_size_lo = len;
+	inode->i_size_high = len >> 32;
+	inode->i_blocks_lo = blocks;
+	inode->osd2.linux2.l_i_blocks_high = blocks >> 32;
+
+	rewind_alloc(alloc);
+
+	return alloc;
+}
+
+/* Allocates enough blocks to hold len bytes, with backing_len bytes in a data
+   buffer, and connects them to an inode.  Returns a pointer to the data
+   buffer. */
+u8 *inode_allocate_data_extents(struct ext4_inode *inode, u64 len,
+	u64 backing_len)
+{
+	struct block_allocation *alloc;
+	u8 *data = NULL;
+
+	alloc = do_inode_allocate_extents(inode, len);
+	if (alloc == NULL) {
+		error("failed to allocate extents for %"PRIu64" bytes", len);
+		return NULL;
+	}
+
+	if (backing_len) {
+		data = extent_create_backing(alloc, backing_len);
+		if (!data)
+			error("failed to create backing for %"PRIu64" bytes", backing_len);
+	}
+
+	free_alloc(alloc);
+
+	return data;
+}
+
+/* Allocates enough blocks to hold len bytes, queues them to be written
+   from a file, and connects them to an inode. */
+void inode_allocate_file_extents(struct ext4_inode *inode, u64 len,
+	const char *filename)
+{
+	struct block_allocation *alloc;
+
+	alloc = do_inode_allocate_extents(inode, len);
+	if (alloc == NULL) {
+		error("failed to allocate extents for %"PRIu64" bytes", len);
+		return;
+	}
+
+	extent_create_backing_file(alloc, len, filename);
+
+	free_alloc(alloc);
+}
+
+/* Allocates enough blocks to hold len bytes and connects them to an inode */
+void inode_allocate_extents(struct ext4_inode *inode, u64 len)
+{
+	struct block_allocation *alloc;
+
+	alloc = do_inode_allocate_extents(inode, len);
+	if (alloc == NULL) {
+		error("failed to allocate extents for %"PRIu64" bytes", len);
+		return;
+	}
+
+	free_alloc(alloc);
+}
diff --git a/distrib/ext4_utils/src/extent.h b/distrib/ext4_utils/src/extent.h
new file mode 100644
index 0000000..a1ddeb1
--- /dev/null
+++ b/distrib/ext4_utils/src/extent.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _EXTENT_H_
+#define _EXTENT_H_
+
+#include "allocate.h"
+#include "ext4_utils.h"
+
+void inode_allocate_extents(struct ext4_inode *inode, u64 len);
+void inode_allocate_file_extents(struct ext4_inode *inode, u64 len,
+	const char *filename);
+u8 *inode_allocate_data_extents(struct ext4_inode *inode, u64 len,
+	u64 backing_len);
+void free_extent_blocks();
+
+#endif
diff --git a/distrib/ext4_utils/src/indirect.c b/distrib/ext4_utils/src/indirect.c
new file mode 100644
index 0000000..cd85a43
--- /dev/null
+++ b/distrib/ext4_utils/src/indirect.c
@@ -0,0 +1,514 @@
+/*
+ * Copyright (C) 2010 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 "ext4_utils.h"
+#include "indirect.h"
+#include "allocate.h"
+
+#include <sparse/sparse.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Creates data buffers for the first backing_len bytes of a block allocation
+   and queues them to be written */
+static u8 *create_backing(struct block_allocation *alloc,
+		unsigned long backing_len)
+{
+	if (DIV_ROUND_UP(backing_len, info.block_size) > EXT4_NDIR_BLOCKS)
+		critical_error("indirect backing larger than %d blocks", EXT4_NDIR_BLOCKS);
+
+	u8 *data = calloc(backing_len, 1);
+	if (!data)
+		critical_error_errno("calloc");
+
+	u8 *ptr = data;
+	for (; alloc != NULL && backing_len > 0; get_next_region(alloc)) {
+		u32 region_block;
+		u32 region_len;
+		u32 len;
+		get_region(alloc, &region_block, &region_len);
+
+		len = min(region_len * info.block_size, backing_len);
+
+		sparse_file_add_data(ext4_sparse_file, ptr, len, region_block);
+		ptr += len;
+		backing_len -= len;
+	}
+
+	return data;
+}
+
+static void reserve_indirect_block(struct block_allocation *alloc, int len)
+{
+	if (reserve_oob_blocks(alloc, 1)) {
+		error("failed to reserve oob block");
+		return;
+	}
+
+	if (advance_blocks(alloc, len)) {
+		error("failed to advance %d blocks", len);
+		return;
+	}
+}
+
+static void reserve_dindirect_block(struct block_allocation *alloc, int len)
+{
+	if (reserve_oob_blocks(alloc, 1)) {
+		error("failed to reserve oob block");
+		return;
+	}
+
+	while (len > 0) {
+		int ind_block_len = min((int)aux_info.blocks_per_ind, len);
+
+		reserve_indirect_block(alloc, ind_block_len);
+
+		len -= ind_block_len;
+	}
+
+}
+
+static void reserve_tindirect_block(struct block_allocation *alloc, int len)
+{
+	if (reserve_oob_blocks(alloc, 1)) {
+		error("failed to reserve oob block");
+		return;
+	}
+
+	while (len > 0) {
+		int dind_block_len = min((int)aux_info.blocks_per_dind, len);
+
+		reserve_dindirect_block(alloc, dind_block_len);
+
+		len -= dind_block_len;
+	}
+}
+
+static void fill_indirect_block(u32 *ind_block, int len, struct block_allocation *alloc)
+{
+	int i;
+	for (i = 0; i < len; i++) {
+		ind_block[i] = get_block(alloc, i);
+	}
+}
+
+static void fill_dindirect_block(u32 *dind_block, int len, struct block_allocation *alloc)
+{
+	int i;
+	u32 ind_block;
+
+	for (i = 0; len >  0; i++) {
+		ind_block = get_oob_block(alloc, 0);
+		if (advance_oob_blocks(alloc, 1)) {
+			error("failed to reserve oob block");
+			return;
+		}
+
+		dind_block[i] = ind_block;
+
+		u32 *ind_block_data = calloc(info.block_size, 1);
+		sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
+				ind_block);
+		int ind_block_len = min((int)aux_info.blocks_per_ind, len);
+
+		fill_indirect_block(ind_block_data, ind_block_len, alloc);
+
+		if (advance_blocks(alloc, ind_block_len)) {
+			error("failed to advance %d blocks", ind_block_len);
+			return;
+		}
+
+		len -= ind_block_len;
+	}
+}
+
+static void fill_tindirect_block(u32 *tind_block, int len, struct block_allocation *alloc)
+{
+	int i;
+	u32 dind_block;
+
+	for (i = 0; len > 0; i++) {
+		dind_block = get_oob_block(alloc, 0);
+		if (advance_oob_blocks(alloc, 1)) {
+			error("failed to reserve oob block");
+			return;
+		}
+
+		tind_block[i] = dind_block;
+
+		u32 *dind_block_data = calloc(info.block_size, 1);
+		sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
+				dind_block);
+		int dind_block_len = min((int)aux_info.blocks_per_dind, len);
+
+		fill_dindirect_block(dind_block_data, dind_block_len, alloc);
+
+		len -= dind_block_len;
+	}
+}
+
+/* Given an allocation, attach as many blocks as possible to direct inode
+   blocks, and return the rest */
+static int inode_attach_direct_blocks(struct ext4_inode *inode,
+		struct block_allocation *alloc, u32 *block_len)
+{
+	int len = min(*block_len, EXT4_NDIR_BLOCKS);
+	int i;
+
+	for (i = 0; i < len; i++) {
+		inode->i_block[i] = get_block(alloc, i);
+	}
+
+	if (advance_blocks(alloc, len)) {
+		error("failed to advance %d blocks", len);
+		return -1;
+	}
+
+	*block_len -= len;
+	return 0;
+}
+
+/* Given an allocation, attach as many blocks as possible to indirect blocks,
+   and return the rest
+   Assumes that the blocks necessary to hold the indirect blocks were included
+   as part of the allocation */
+static int inode_attach_indirect_blocks(struct ext4_inode *inode,
+		struct block_allocation *alloc, u32 *block_len)
+{
+	int len = min(*block_len, aux_info.blocks_per_ind);
+
+	int ind_block = get_oob_block(alloc, 0);
+	inode->i_block[EXT4_IND_BLOCK] = ind_block;
+
+	if (advance_oob_blocks(alloc, 1)) {
+		error("failed to advance oob block");
+		return -1;
+	}
+
+	u32 *ind_block_data = calloc(info.block_size, 1);
+	sparse_file_add_data(ext4_sparse_file, ind_block_data, info.block_size,
+			ind_block);
+
+	fill_indirect_block(ind_block_data, len, alloc);
+
+	if (advance_blocks(alloc, len)) {
+		error("failed to advance %d blocks", len);
+		return -1;
+	}
+
+	*block_len -= len;
+	return 0;
+}
+
+/* Given an allocation, attach as many blocks as possible to doubly indirect
+   blocks, and return the rest.
+   Assumes that the blocks necessary to hold the indirect and doubly indirect
+   blocks were included as part of the allocation */
+static int inode_attach_dindirect_blocks(struct ext4_inode *inode,
+		struct block_allocation *alloc, u32 *block_len)
+{
+	int len = min(*block_len, aux_info.blocks_per_dind);
+
+	int dind_block = get_oob_block(alloc, 0);
+	inode->i_block[EXT4_DIND_BLOCK] = dind_block;
+
+	if (advance_oob_blocks(alloc, 1)) {
+		error("failed to advance oob block");
+		return -1;
+	}
+
+	u32 *dind_block_data = calloc(info.block_size, 1);
+	sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
+			dind_block);
+
+	fill_dindirect_block(dind_block_data, len, alloc);
+
+	if (advance_blocks(alloc, len)) {
+		error("failed to advance %d blocks", len);
+		return -1;
+	}
+
+	*block_len -= len;
+	return 0;
+}
+
+/* Given an allocation, attach as many blocks as possible to triply indirect
+   blocks, and return the rest.
+   Assumes that the blocks necessary to hold the indirect, doubly indirect and
+   triply indirect blocks were included as part of the allocation */
+static int inode_attach_tindirect_blocks(struct ext4_inode *inode,
+		struct block_allocation *alloc, u32 *block_len)
+{
+	int len = min(*block_len, aux_info.blocks_per_tind);
+
+	int tind_block = get_oob_block(alloc, 0);
+	inode->i_block[EXT4_TIND_BLOCK] = tind_block;
+
+	if (advance_oob_blocks(alloc, 1)) {
+		error("failed to advance oob block");
+		return -1;
+	}
+
+	u32 *tind_block_data = calloc(info.block_size, 1);
+	sparse_file_add_data(ext4_sparse_file, tind_block_data, info.block_size,
+			tind_block);
+
+	fill_tindirect_block(tind_block_data, len, alloc);
+
+	if (advance_blocks(alloc, len)) {
+		error("failed to advance %d blocks", len);
+		return -1;
+	}
+
+	*block_len -= len;
+	return 0;
+}
+
+static void reserve_all_indirect_blocks(struct block_allocation *alloc, u32 len)
+{
+	if (len <= EXT4_NDIR_BLOCKS)
+		return;
+
+	len -= EXT4_NDIR_BLOCKS;
+	advance_blocks(alloc, EXT4_NDIR_BLOCKS);
+
+	u32 ind_block_len = min(aux_info.blocks_per_ind, len);
+	reserve_indirect_block(alloc, ind_block_len);
+
+	len -= ind_block_len;
+	if (len == 0)
+		return;
+
+	u32 dind_block_len = min(aux_info.blocks_per_dind, len);
+	reserve_dindirect_block(alloc, dind_block_len);
+
+	len -= dind_block_len;
+	if (len == 0)
+		return;
+
+	u32 tind_block_len = min(aux_info.blocks_per_tind, len);
+	reserve_tindirect_block(alloc, tind_block_len);
+
+	len -= tind_block_len;
+	if (len == 0)
+		return;
+
+	error("%d blocks remaining", len);
+}
+
+static u32 indirect_blocks_needed(u32 len)
+{
+	u32 ind = 0;
+
+	if (len <= EXT4_NDIR_BLOCKS)
+		return ind;
+
+	len -= EXT4_NDIR_BLOCKS;
+
+	/* We will need an indirect block for the rest of the blocks */
+	ind += DIV_ROUND_UP(len, aux_info.blocks_per_ind);
+
+	if (len <= aux_info.blocks_per_ind)
+		return ind;
+
+	len -= aux_info.blocks_per_ind;
+
+	ind += DIV_ROUND_UP(len, aux_info.blocks_per_dind);
+
+	if (len <= aux_info.blocks_per_dind)
+		return ind;
+
+	len -= aux_info.blocks_per_dind;
+
+	ind += DIV_ROUND_UP(len, aux_info.blocks_per_tind);
+
+	if (len <= aux_info.blocks_per_tind)
+		return ind;
+
+	critical_error("request too large");
+	return 0;
+}
+
+static int do_inode_attach_indirect(struct ext4_inode *inode,
+		struct block_allocation *alloc, u32 block_len)
+{
+	u32 count = block_len;
+
+	if (inode_attach_direct_blocks(inode, alloc, &count)) {
+		error("failed to attach direct blocks to inode");
+		return -1;
+	}
+
+	if (count > 0) {
+		if (inode_attach_indirect_blocks(inode, alloc, &count)) {
+			error("failed to attach indirect blocks to inode");
+			return -1;
+		}
+	}
+
+	if (count > 0) {
+		if (inode_attach_dindirect_blocks(inode, alloc, &count)) {
+			error("failed to attach dindirect blocks to inode");
+			return -1;
+		}
+	}
+
+	if (count > 0) {
+		if (inode_attach_tindirect_blocks(inode, alloc, &count)) {
+			error("failed to attach tindirect blocks to inode");
+			return -1;
+		}
+	}
+
+	if (count) {
+		error("blocks left after triply-indirect allocation");
+		return -1;
+	}
+
+	rewind_alloc(alloc);
+
+	return 0;
+}
+
+static struct block_allocation *do_inode_allocate_indirect(
+		u32 block_len)
+{
+	u32 indirect_len = indirect_blocks_needed(block_len);
+
+	struct block_allocation *alloc = allocate_blocks(block_len + indirect_len);
+
+	if (alloc == NULL) {
+		error("Failed to allocate %d blocks", block_len + indirect_len);
+		return NULL;
+	}
+
+	return alloc;
+}
+
+/* Allocates enough blocks to hold len bytes and connects them to an inode */
+void inode_allocate_indirect(struct ext4_inode *inode, unsigned long len)
+{
+	struct block_allocation *alloc;
+	u32 block_len = DIV_ROUND_UP(len, info.block_size);
+	u32 indirect_len = indirect_blocks_needed(block_len);
+
+	alloc = do_inode_allocate_indirect(block_len);
+	if (alloc == NULL) {
+		error("failed to allocate extents for %lu bytes", len);
+		return;
+	}
+
+	reserve_all_indirect_blocks(alloc, block_len);
+	rewind_alloc(alloc);
+
+	if (do_inode_attach_indirect(inode, alloc, block_len))
+		error("failed to attach blocks to indirect inode");
+
+	inode->i_flags = 0;
+	inode->i_blocks_lo = (block_len + indirect_len) * info.block_size / 512;
+	inode->i_size_lo = len;
+
+	free_alloc(alloc);
+}
+
+void inode_attach_resize(struct ext4_inode *inode,
+		struct block_allocation *alloc)
+{
+	u32 block_len = block_allocation_len(alloc);
+	u32 superblocks = block_len / info.bg_desc_reserve_blocks;
+	u32 i, j;
+	u64 blocks;
+	u64 size;
+
+	if (block_len % info.bg_desc_reserve_blocks)
+		critical_error("reserved blocks not a multiple of %d",
+				info.bg_desc_reserve_blocks);
+
+	append_oob_allocation(alloc, 1);
+	u32 dind_block = get_oob_block(alloc, 0);
+
+	u32 *dind_block_data = calloc(info.block_size, 1);
+	if (!dind_block_data)
+		critical_error_errno("calloc");
+	sparse_file_add_data(ext4_sparse_file, dind_block_data, info.block_size,
+			dind_block);
+
+	u32 *ind_block_data = calloc(info.block_size, info.bg_desc_reserve_blocks);
+	if (!ind_block_data)
+		critical_error_errno("calloc");
+	sparse_file_add_data(ext4_sparse_file, ind_block_data,
+			info.block_size * info.bg_desc_reserve_blocks,
+			get_block(alloc, 0));
+
+	for (i = 0; i < info.bg_desc_reserve_blocks; i++) {
+		int r = (i - aux_info.bg_desc_blocks) % info.bg_desc_reserve_blocks;
+		if (r < 0)
+			r += info.bg_desc_reserve_blocks;
+
+		dind_block_data[i] = get_block(alloc, r);
+
+		for (j = 1; j < superblocks; j++) {
+			u32 b = j * info.bg_desc_reserve_blocks + r;
+			ind_block_data[r * aux_info.blocks_per_ind + j - 1] = get_block(alloc, b);
+		}
+	}
+
+	u32 last_block = EXT4_NDIR_BLOCKS + aux_info.blocks_per_ind +
+			aux_info.blocks_per_ind * (info.bg_desc_reserve_blocks - 1) +
+			superblocks - 2;
+
+	blocks = ((u64)block_len + 1) * info.block_size / 512;
+	size = (u64)last_block * info.block_size;
+
+	inode->i_block[EXT4_DIND_BLOCK] = dind_block;
+	inode->i_flags = 0;
+	inode->i_blocks_lo = blocks;
+	inode->osd2.linux2.l_i_blocks_high = blocks >> 32;
+	inode->i_size_lo = size;
+	inode->i_size_high = size >> 32;
+}
+
+/* Allocates enough blocks to hold len bytes, with backing_len bytes in a data
+   buffer, and connects them to an inode.  Returns a pointer to the data
+   buffer. */
+u8 *inode_allocate_data_indirect(struct ext4_inode *inode, unsigned long len,
+		unsigned long backing_len)
+{
+	struct block_allocation *alloc;
+	u32 block_len = DIV_ROUND_UP(len, info.block_size);
+	u8 *data = NULL;
+
+	alloc = do_inode_allocate_indirect(block_len);
+	if (alloc == NULL) {
+		error("failed to allocate extents for %lu bytes", len);
+		return NULL;
+	}
+
+	if (backing_len) {
+		data = create_backing(alloc, backing_len);
+		if (!data)
+			error("failed to create backing for %lu bytes", backing_len);
+	}
+
+	rewind_alloc(alloc);
+	if (do_inode_attach_indirect(inode, alloc, block_len))
+		error("failed to attach blocks to indirect inode");
+
+	free_alloc(alloc);
+
+	return data;
+}
diff --git a/distrib/ext4_utils/src/indirect.h b/distrib/ext4_utils/src/indirect.h
new file mode 100644
index 0000000..cee8979
--- /dev/null
+++ b/distrib/ext4_utils/src/indirect.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _INDIRECT_H_
+#define _INDIRECT_H_
+
+#include "allocate.h"
+
+void inode_allocate_indirect(struct ext4_inode *inode, unsigned long len);
+u8 *inode_allocate_data_indirect(struct ext4_inode *inode, unsigned long len,
+	unsigned long backing_len);
+void inode_attach_resize(struct ext4_inode *inode,
+		struct block_allocation *alloc);
+void free_indirect_blocks();
+
+#endif
diff --git a/distrib/ext4_utils/src/jbd2.h b/distrib/ext4_utils/src/jbd2.h
new file mode 100644
index 0000000..bac58c2
--- /dev/null
+++ b/distrib/ext4_utils/src/jbd2.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+ ****************************************************************************
+ ***
+ ***   This header was automatically generated from a Linux kernel header
+ ***   of the same name, to make information necessary for userspace to
+ ***   call into the kernel available to libc.  It contains only constants,
+ ***   structures, and macros generated from the original header, and thus,
+ ***   contains no copyrightable information.
+ ***
+ ****************************************************************************
+ ****************************************************************************/
+#ifndef _LINUX_JBD2_H
+#define _LINUX_JBD2_H
+
+#define JBD2_DEBUG
+#define jfs_debug jbd_debug
+
+#define journal_oom_retry 1
+
+#undef JBD2_PARANOID_IOFAIL
+
+#define JBD2_DEFAULT_MAX_COMMIT_AGE 5
+
+#define jbd_debug(f, a...)  
+
+#define JBD2_MIN_JOURNAL_BLOCKS 1024
+
+#define JBD2_MAGIC_NUMBER 0xc03b3998U  
+
+#define JBD2_DESCRIPTOR_BLOCK 1
+#define JBD2_COMMIT_BLOCK 2
+#define JBD2_SUPERBLOCK_V1 3
+#define JBD2_SUPERBLOCK_V2 4
+#define JBD2_REVOKE_BLOCK 5
+
+typedef struct journal_header_s
+{
+ __be32 h_magic;
+ __be32 h_blocktype;
+ __be32 h_sequence;
+} journal_header_t;
+
+#define JBD2_CRC32_CHKSUM 1
+#define JBD2_MD5_CHKSUM 2
+#define JBD2_SHA1_CHKSUM 3
+
+#define JBD2_CRC32_CHKSUM_SIZE 4
+
+#define JBD2_CHECKSUM_BYTES (32 / sizeof(__u32))
+
+struct commit_header {
+ __be32 h_magic;
+ __be32 h_blocktype;
+ __be32 h_sequence;
+ unsigned char h_chksum_type;
+ unsigned char h_chksum_size;
+ unsigned char h_padding[2];
+ __be32 h_chksum[JBD2_CHECKSUM_BYTES];
+ __be64 h_commit_sec;
+ __be32 h_commit_nsec;
+};
+
+typedef struct journal_block_tag_s
+{
+ __be32 t_blocknr;
+ __be32 t_flags;
+ __be32 t_blocknr_high;
+} journal_block_tag_t;
+
+#define JBD2_TAG_SIZE32 (offsetof(journal_block_tag_t, t_blocknr_high))
+#define JBD2_TAG_SIZE64 (sizeof(journal_block_tag_t))
+
+typedef struct jbd2_journal_revoke_header_s
+{
+ journal_header_t r_header;
+ __be32 r_count;
+} jbd2_journal_revoke_header_t;
+
+#define JBD2_FLAG_ESCAPE 1  
+#define JBD2_FLAG_SAME_UUID 2  
+#define JBD2_FLAG_DELETED 4  
+#define JBD2_FLAG_LAST_TAG 8  
+
+typedef struct journal_superblock_s
+{
+
+ journal_header_t s_header;
+
+ __be32 s_blocksize;
+ __be32 s_maxlen;
+ __be32 s_first;
+
+ __be32 s_sequence;
+ __be32 s_start;
+
+ __be32 s_errno;
+
+ __be32 s_feature_compat;
+ __be32 s_feature_incompat;
+ __be32 s_feature_ro_compat;
+
+ __u8 s_uuid[16];
+
+ __be32 s_nr_users;
+
+ __be32 s_dynsuper;
+
+ __be32 s_max_transaction;
+ __be32 s_max_trans_data;
+
+ __u32 s_padding[44];
+
+ __u8 s_users[16*48];
+
+} journal_superblock_t;
+
+#define JBD2_HAS_COMPAT_FEATURE(j,mask)   ((j)->j_format_version >= 2 &&   ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask))))
+#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask)   ((j)->j_format_version >= 2 &&   ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask))))
+#define JBD2_HAS_INCOMPAT_FEATURE(j,mask)   ((j)->j_format_version >= 2 &&   ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask))))
+
+#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001
+
+#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001
+#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002
+#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004
+
+#define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM
+#define JBD2_KNOWN_ROCOMPAT_FEATURES 0
+#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE |   JBD2_FEATURE_INCOMPAT_64BIT |   JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT)
+
+#define BJ_None 0  
+#define BJ_Metadata 1  
+#define BJ_Forget 2  
+#define BJ_IO 3  
+#define BJ_Shadow 4  
+#define BJ_LogCtl 5  
+#define BJ_Reserved 6  
+#define BJ_Types 7
+
+#endif
+
diff --git a/distrib/ext4_utils/src/make_ext4fs.c b/distrib/ext4_utils/src/make_ext4fs.c
new file mode 100644
index 0000000..6a0f875
--- /dev/null
+++ b/distrib/ext4_utils/src/make_ext4fs.c
@@ -0,0 +1,639 @@
+/*
+ * Copyright (C) 2010 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 "make_ext4fs.h"
+#include "ext4_utils.h"
+#include "allocate.h"
+#include "contents.h"
+#include "uuid.h"
+#include "wipe.h"
+
+#include <sparse/sparse.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef USE_MINGW
+
+#include <winsock2.h>
+
+/* These match the Linux definitions of these flags.
+   L_xx is defined to avoid conflicting with the win32 versions.
+*/
+#define L_S_IRUSR 00400
+#define L_S_IWUSR 00200
+#define L_S_IXUSR 00100
+#define S_IRWXU (L_S_IRUSR | L_S_IWUSR | L_S_IXUSR)
+#define S_IRGRP 00040
+#define S_IWGRP 00020
+#define S_IXGRP 00010
+#define S_IRWXG (S_IRGRP | S_IWGRP | S_IXGRP)
+#define S_IROTH 00004
+#define S_IWOTH 00002
+#define S_IXOTH 00001
+#define S_IRWXO (S_IROTH | S_IWOTH | S_IXOTH)
+#define S_ISUID 0004000
+#define S_ISGID 0002000
+#define S_ISVTX 0001000
+
+#else
+
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+
+#define O_BINARY 0
+
+#endif
+
+/* TODO: Not implemented:
+   Allocating blocks in the same block group as the file inode
+   Hash or binary tree directories
+   Special files: sockets, devices, fifos
+ */
+
+static int filter_dot(const struct dirent *d)
+{
+	return (strcmp(d->d_name, "..") && strcmp(d->d_name, "."));
+}
+
+static u32 build_default_directory_structure(const char *dir_path,
+					     struct selabel_handle *sehnd)
+{
+	u32 inode;
+	u32 root_inode;
+	struct dentry dentries = {
+			.filename = "lost+found",
+			.file_type = EXT4_FT_DIR,
+			.mode = S_IRWXU,
+			.uid = 0,
+			.gid = 0,
+			.mtime = 0,
+	};
+	root_inode = make_directory(0, 1, &dentries, 1);
+	inode = make_directory(root_inode, 0, NULL, 0);
+	*dentries.inode = inode;
+	inode_set_permissions(inode, dentries.mode,
+		dentries.uid, dentries.gid, dentries.mtime);
+
+#ifndef USE_MINGW
+	if (sehnd) {
+		char *path = NULL;
+		char *secontext = NULL;
+
+		asprintf(&path, "%slost+found", dir_path);
+		if (selabel_lookup(sehnd, &secontext, path, S_IFDIR) < 0) {
+			error("cannot lookup security context for %s", path);
+		} else {
+			inode_set_selinux(inode, secontext);
+			freecon(secontext);
+		}
+		free(path);
+	}
+#endif
+
+	return root_inode;
+}
+
+#ifndef USE_MINGW
+/* Read a local directory and create the same tree in the generated filesystem.
+   Calls itself recursively with each directory in the given directory.
+   full_path is an absolute or relative path, with a trailing slash, to the
+   directory on disk that should be copied, or NULL if this is a directory
+   that does not exist on disk (e.g. lost+found).
+   dir_path is an absolute path, with trailing slash, to the same directory
+   if the image were mounted at the specified mount point */
+static u32 build_directory_structure(const char *full_path, const char *dir_path,
+		u32 dir_inode, fs_config_func_t fs_config_func,
+		struct selabel_handle *sehnd, int verbose)
+{
+	int entries = 0;
+	struct dentry *dentries;
+	struct dirent **namelist = NULL;
+	struct stat stat;
+	int ret;
+	int i;
+	u32 inode;
+	u32 entry_inode;
+	u32 dirs = 0;
+	bool needs_lost_and_found = false;
+
+	if (full_path) {
+		entries = scandir(full_path, &namelist, filter_dot, (void*)alphasort);
+		if (entries < 0) {
+			error_errno("scandir");
+			return EXT4_ALLOCATE_FAILED;
+		}
+	}
+
+	if (dir_inode == 0) {
+		/* root directory, check if lost+found already exists */
+		for (i = 0; i < entries; i++)
+			if (strcmp(namelist[i]->d_name, "lost+found") == 0)
+				break;
+		if (i == entries)
+			needs_lost_and_found = true;
+	}
+
+	dentries = calloc(entries, sizeof(struct dentry));
+	if (dentries == NULL)
+		critical_error_errno("malloc");
+
+	for (i = 0; i < entries; i++) {
+		dentries[i].filename = strdup(namelist[i]->d_name);
+		if (dentries[i].filename == NULL)
+			critical_error_errno("strdup");
+
+		asprintf(&dentries[i].path, "%s%s", dir_path, namelist[i]->d_name);
+		asprintf(&dentries[i].full_path, "%s%s", full_path, namelist[i]->d_name);
+
+		free(namelist[i]);
+
+		ret = lstat(dentries[i].full_path, &stat);
+		if (ret < 0) {
+			error_errno("lstat");
+			i--;
+			entries--;
+			continue;
+		}
+
+		dentries[i].size = stat.st_size;
+		dentries[i].mode = stat.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
+		dentries[i].mtime = stat.st_mtime;
+		uint64_t capabilities;
+		if (fs_config_func != NULL) {
+#ifdef ANDROID
+			unsigned int mode = 0;
+			unsigned int uid = 0;
+			unsigned int gid = 0;
+			int dir = S_ISDIR(stat.st_mode);
+			fs_config_func(dentries[i].path, dir, &uid, &gid, &mode, &capabilities);
+			dentries[i].mode = mode;
+			dentries[i].uid = uid;
+			dentries[i].gid = gid;
+			dentries[i].capabilities = capabilities;
+#else
+			error("can't set android permissions - built without android support");
+#endif
+		}
+#ifndef USE_MINGW
+		if (sehnd) {
+			if (selabel_lookup(sehnd, &dentries[i].secon, dentries[i].path, stat.st_mode) < 0) {
+				error("cannot lookup security context for %s", dentries[i].path);
+			}
+
+			if (dentries[i].secon && verbose)
+				printf("Labeling %s as %s\n", dentries[i].path, dentries[i].secon);
+		}
+#endif
+
+		if (S_ISREG(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_REG_FILE;
+		} else if (S_ISDIR(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_DIR;
+			dirs++;
+		} else if (S_ISCHR(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_CHRDEV;
+		} else if (S_ISBLK(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_BLKDEV;
+		} else if (S_ISFIFO(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_FIFO;
+		} else if (S_ISSOCK(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_SOCK;
+		} else if (S_ISLNK(stat.st_mode)) {
+			dentries[i].file_type = EXT4_FT_SYMLINK;
+			dentries[i].link = calloc(info.block_size, 1);
+			readlink(dentries[i].full_path, dentries[i].link, info.block_size - 1);
+		} else {
+			error("unknown file type on %s", dentries[i].path);
+			i--;
+			entries--;
+		}
+	}
+	free(namelist);
+
+	if (needs_lost_and_found) {
+		/* insert a lost+found directory at the beginning of the dentries */
+		struct dentry *tmp = calloc(entries + 1, sizeof(struct dentry));
+		memset(tmp, 0, sizeof(struct dentry));
+		memcpy(tmp + 1, dentries, entries * sizeof(struct dentry));
+		dentries = tmp;
+
+		dentries[0].filename = strdup("lost+found");
+		asprintf(&dentries[0].path, "%slost+found", dir_path);
+		dentries[0].full_path = NULL;
+		dentries[0].size = 0;
+		dentries[0].mode = S_IRWXU;
+		dentries[0].file_type = EXT4_FT_DIR;
+		dentries[0].uid = 0;
+		dentries[0].gid = 0;
+		if (sehnd) {
+			if (selabel_lookup(sehnd, &dentries[0].secon, dentries[0].path, dentries[0].mode) < 0)
+				error("cannot lookup security context for %s", dentries[0].path);
+		}
+		entries++;
+		dirs++;
+	}
+
+	inode = make_directory(dir_inode, entries, dentries, dirs);
+
+	for (i = 0; i < entries; i++) {
+		if (dentries[i].file_type == EXT4_FT_REG_FILE) {
+			entry_inode = make_file(dentries[i].full_path, dentries[i].size);
+		} else if (dentries[i].file_type == EXT4_FT_DIR) {
+			char *subdir_full_path = NULL;
+			char *subdir_dir_path;
+			if (dentries[i].full_path) {
+				ret = asprintf(&subdir_full_path, "%s/", dentries[i].full_path);
+				if (ret < 0)
+					critical_error_errno("asprintf");
+			}
+			ret = asprintf(&subdir_dir_path, "%s/", dentries[i].path);
+			if (ret < 0)
+				critical_error_errno("asprintf");
+			entry_inode = build_directory_structure(subdir_full_path,
+					subdir_dir_path, inode, fs_config_func, sehnd, verbose);
+			free(subdir_full_path);
+			free(subdir_dir_path);
+		} else if (dentries[i].file_type == EXT4_FT_SYMLINK) {
+			entry_inode = make_link(dentries[i].link);
+		} else {
+			error("unknown file type on %s", dentries[i].path);
+			entry_inode = 0;
+		}
+		*dentries[i].inode = entry_inode;
+
+		ret = inode_set_permissions(entry_inode, dentries[i].mode,
+			dentries[i].uid, dentries[i].gid,
+			dentries[i].mtime);
+		if (ret)
+			error("failed to set permissions on %s\n", dentries[i].path);
+
+		/*
+		 * It's important to call inode_set_selinux() before
+		 * inode_set_capabilities(). Extended attributes need to
+		 * be stored sorted order, and we guarantee this by making
+		 * the calls in the proper order.
+		 * Please see xattr_assert_sane() in contents.c
+		 */
+		ret = inode_set_selinux(entry_inode, dentries[i].secon);
+		if (ret)
+			error("failed to set SELinux context on %s\n", dentries[i].path);
+		ret = inode_set_capabilities(entry_inode, dentries[i].capabilities);
+		if (ret)
+			error("failed to set capability on %s\n", dentries[i].path);
+
+		free(dentries[i].path);
+		free(dentries[i].full_path);
+		free(dentries[i].link);
+		free((void *)dentries[i].filename);
+		free(dentries[i].secon);
+	}
+
+	free(dentries);
+	return inode;
+}
+#endif
+
+static u32 compute_block_size()
+{
+	return 4096;
+}
+
+static u32 compute_journal_blocks()
+{
+	u32 journal_blocks = DIV_ROUND_UP(info.len, info.block_size) / 64;
+	if (journal_blocks < 1024)
+		journal_blocks = 1024;
+	if (journal_blocks > 32768)
+		journal_blocks = 32768;
+	return journal_blocks;
+}
+
+static u32 compute_blocks_per_group()
+{
+	return info.block_size * 8;
+}
+
+static u32 compute_inodes()
+{
+	return DIV_ROUND_UP(info.len, info.block_size) / 4;
+}
+
+static u32 compute_inodes_per_group()
+{
+	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
+	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
+	u32 inodes = DIV_ROUND_UP(info.inodes, block_groups);
+	inodes = ALIGN(inodes, (info.block_size / info.inode_size));
+
+	/* After properly rounding up the number of inodes/group,
+	 * make sure to update the total inodes field in the info struct.
+	 */
+	info.inodes = inodes * block_groups;
+
+	return inodes;
+}
+
+static u32 compute_bg_desc_reserve_blocks()
+{
+	u32 blocks = DIV_ROUND_UP(info.len, info.block_size);
+	u32 block_groups = DIV_ROUND_UP(blocks, info.blocks_per_group);
+	u32 bg_desc_blocks = DIV_ROUND_UP(block_groups * sizeof(struct ext2_group_desc),
+			info.block_size);
+
+	u32 bg_desc_reserve_blocks =
+			DIV_ROUND_UP(block_groups * 1024 * sizeof(struct ext2_group_desc),
+					info.block_size) - bg_desc_blocks;
+
+	if (bg_desc_reserve_blocks > info.block_size / sizeof(u32))
+		bg_desc_reserve_blocks = info.block_size / sizeof(u32);
+
+	return bg_desc_reserve_blocks;
+}
+
+void reset_ext4fs_info() {
+    // Reset all the global data structures used by make_ext4fs so it
+    // can be called again.
+    memset(&info, 0, sizeof(info));
+    memset(&aux_info, 0, sizeof(aux_info));
+
+    if (ext4_sparse_file) {
+        sparse_file_destroy(ext4_sparse_file);
+        ext4_sparse_file = NULL;
+    }
+}
+
+int make_ext4fs_sparse_fd(int fd, long long len,
+                const char *mountpoint, struct selabel_handle *sehnd)
+{
+	reset_ext4fs_info();
+	info.len = len;
+
+	return make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 1, 0, 0, sehnd, 0);
+}
+
+int make_ext4fs(const char *filename, long long len,
+                const char *mountpoint, struct selabel_handle *sehnd)
+{
+	int fd;
+	int status;
+
+	reset_ext4fs_info();
+	info.len = len;
+
+	fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+	if (fd < 0) {
+		error_errno("open");
+		return EXIT_FAILURE;
+	}
+
+	status = make_ext4fs_internal(fd, NULL, mountpoint, NULL, 0, 0, 0, 1, sehnd, 0);
+	close(fd);
+
+	return status;
+}
+
+/* return a newly-malloc'd string that is a copy of str.  The new string
+   is guaranteed to have a trailing slash.  If absolute is true, the new string
+   is also guaranteed to have a leading slash.
+*/
+static char *canonicalize_slashes(const char *str, bool absolute)
+{
+	char *ret;
+	int len = strlen(str);
+	int newlen = len;
+	char *ptr;
+
+	if (len == 0) {
+		if (absolute)
+			return strdup("/");
+		else
+			return strdup("");
+	}
+
+	if (str[0] != '/' && absolute) {
+		newlen++;
+	}
+	if (str[len - 1] != '/') {
+		newlen++;
+	}
+	ret = malloc(newlen + 1);
+	if (!ret) {
+		critical_error("malloc");
+	}
+
+	ptr = ret;
+	if (str[0] != '/' && absolute) {
+		*ptr++ = '/';
+	}
+
+	strcpy(ptr, str);
+	ptr += len;
+
+	if (str[len - 1] != '/') {
+		*ptr++ = '/';
+	}
+
+	if (ptr != ret + newlen) {
+		critical_error("assertion failed\n");
+	}
+
+	*ptr = '\0';
+
+	return ret;
+}
+
+static char *canonicalize_abs_slashes(const char *str)
+{
+	return canonicalize_slashes(str, true);
+}
+
+static char *canonicalize_rel_slashes(const char *str)
+{
+	return canonicalize_slashes(str, false);
+}
+
+int make_ext4fs_internal(int fd, const char *_directory,
+                         const char *_mountpoint, fs_config_func_t fs_config_func, int gzip,
+                         int sparse, int crc, int wipe,
+                         struct selabel_handle *sehnd, int verbose)
+{
+	u32 root_inode_num;
+	u16 root_mode;
+	char *mountpoint;
+	char *directory = NULL;
+
+	if (setjmp(setjmp_env))
+		return EXIT_FAILURE; /* Handle a call to longjmp() */
+
+	if (_mountpoint == NULL) {
+		mountpoint = strdup("");
+	} else {
+		mountpoint = canonicalize_abs_slashes(_mountpoint);
+	}
+
+	if (_directory) {
+		directory = canonicalize_rel_slashes(_directory);
+	}
+
+	if (info.len <= 0)
+		info.len = get_file_size(fd);
+
+	if (info.len <= 0) {
+		fprintf(stderr, "Need size of filesystem\n");
+		return EXIT_FAILURE;
+	}
+
+	if (info.block_size <= 0)
+		info.block_size = compute_block_size();
+
+	/* Round down the filesystem length to be a multiple of the block size */
+	info.len &= ~((u64)info.block_size - 1);
+
+	if (info.journal_blocks == 0)
+		info.journal_blocks = compute_journal_blocks();
+
+	if (info.no_journal == 0)
+		info.feat_compat = EXT4_FEATURE_COMPAT_HAS_JOURNAL;
+	else
+		info.journal_blocks = 0;
+
+	if (info.blocks_per_group <= 0)
+		info.blocks_per_group = compute_blocks_per_group();
+
+	if (info.inodes <= 0)
+		info.inodes = compute_inodes();
+
+	if (info.inode_size <= 0)
+		info.inode_size = 256;
+
+	if (info.label == NULL)
+		info.label = "";
+
+	info.inodes_per_group = compute_inodes_per_group();
+
+	info.feat_compat |=
+			EXT4_FEATURE_COMPAT_RESIZE_INODE |
+			EXT4_FEATURE_COMPAT_EXT_ATTR;
+
+	info.feat_ro_compat |=
+			EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER |
+			EXT4_FEATURE_RO_COMPAT_LARGE_FILE |
+			EXT4_FEATURE_RO_COMPAT_GDT_CSUM;
+
+	info.feat_incompat |=
+			EXT4_FEATURE_INCOMPAT_EXTENTS |
+			EXT4_FEATURE_INCOMPAT_FILETYPE;
+
+
+	info.bg_desc_reserve_blocks = compute_bg_desc_reserve_blocks();
+
+	printf("Creating filesystem with parameters:\n");
+	printf("    Size: %"PRIu64"\n", info.len);
+	printf("    Block size: %d\n", info.block_size);
+	printf("    Blocks per group: %d\n", info.blocks_per_group);
+	printf("    Inodes per group: %d\n", info.inodes_per_group);
+	printf("    Inode size: %d\n", info.inode_size);
+	printf("    Journal blocks: %d\n", info.journal_blocks);
+	printf("    Label: %s\n", info.label);
+
+	ext4_create_fs_aux_info();
+
+	printf("    Blocks: %"PRIu64"\n", aux_info.len_blocks);
+	printf("    Block groups: %d\n", aux_info.groups);
+	printf("    Reserved block group size: %d\n", info.bg_desc_reserve_blocks);
+
+	ext4_sparse_file = sparse_file_new(info.block_size, info.len);
+
+	block_allocator_init();
+
+	ext4_fill_in_sb();
+
+	if (reserve_inodes(0, 10) == EXT4_ALLOCATE_FAILED)
+		error("failed to reserve first 10 inodes");
+
+	if (info.feat_compat & EXT4_FEATURE_COMPAT_HAS_JOURNAL)
+		ext4_create_journal_inode();
+
+	if (info.feat_compat & EXT4_FEATURE_COMPAT_RESIZE_INODE)
+		ext4_create_resize_inode();
+
+#ifdef USE_MINGW
+	// Windows needs only 'create an empty fs image' functionality
+	assert(!directory);
+	root_inode_num = build_default_directory_structure(mountpoint, sehnd);
+#else
+	if (directory)
+		root_inode_num = build_directory_structure(directory, mountpoint, 0,
+                        fs_config_func, sehnd, verbose);
+	else
+		root_inode_num = build_default_directory_structure(mountpoint, sehnd);
+#endif
+
+	root_mode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+	inode_set_permissions(root_inode_num, root_mode, 0, 0, 0);
+
+#ifndef USE_MINGW
+	if (sehnd) {
+		char *secontext = NULL;
+
+		if (selabel_lookup(sehnd, &secontext, mountpoint, S_IFDIR) < 0) {
+			error("cannot lookup security context for %s", mountpoint);
+		}
+		if (secontext) {
+			if (verbose) {
+				printf("Labeling %s as %s\n", mountpoint, secontext);
+			}
+			inode_set_selinux(root_inode_num, secontext);
+		}
+		freecon(secontext);
+	}
+#endif
+
+	ext4_update_free();
+
+	ext4_queue_sb();
+
+	printf("Created filesystem with %d/%d inodes and %d/%d blocks\n",
+			aux_info.sb->s_inodes_count - aux_info.sb->s_free_inodes_count,
+			aux_info.sb->s_inodes_count,
+			aux_info.sb->s_blocks_count_lo - aux_info.sb->s_free_blocks_count_lo,
+			aux_info.sb->s_blocks_count_lo);
+
+	if (wipe && WIPE_IS_SUPPORTED) {
+		wipe_block_device(fd, info.len);
+	}
+
+	write_ext4_image(fd, gzip, sparse, crc);
+
+	sparse_file_destroy(ext4_sparse_file);
+	ext4_sparse_file = NULL;
+
+	free(mountpoint);
+	free(directory);
+
+	return 0;
+}
diff --git a/distrib/ext4_utils/src/make_ext4fs_main.c b/distrib/ext4_utils/src/make_ext4fs_main.c
new file mode 100644
index 0000000..754e51f
--- /dev/null
+++ b/distrib/ext4_utils/src/make_ext4fs_main.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2010 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 <fcntl.h>
+#include <libgen.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#if defined(__linux__)
+#include <linux/fs.h>
+#elif defined(__APPLE__) && defined(__MACH__)
+#include <sys/disk.h>
+#endif
+
+#ifdef ANDROID
+#include <private/android_filesystem_config.h>
+#endif
+
+#ifndef USE_MINGW
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include <selinux/android.h>
+#else
+struct selabel_handle;
+#endif
+
+#include "make_ext4fs.h"
+#include "ext4_utils.h"
+
+#ifndef USE_MINGW /* O_BINARY is windows-specific flag */
+#define O_BINARY 0
+#endif
+
+extern struct fs_info info;
+
+
+static void usage(char *path)
+{
+	fprintf(stderr, "%s [ -l <len> ] [ -j <journal size> ] [ -b <block_size> ]\n", basename(path));
+	fprintf(stderr, "    [ -g <blocks per group> ] [ -i <inodes> ] [ -I <inode size> ]\n");
+	fprintf(stderr, "    [ -L <label> ] [ -f ] [ -a <android mountpoint> ]\n");
+	fprintf(stderr, "    [ -S file_contexts ]\n");
+	fprintf(stderr, "    [ -z | -s ] [ -w ] [ -c ] [ -J ] [ -v ]\n");
+	fprintf(stderr, "    <filename> [<directory>]\n");
+}
+
+int main(int argc, char **argv)
+{
+	int opt;
+	const char *filename = NULL;
+	const char *directory = NULL;
+	char *mountpoint = NULL;
+	fs_config_func_t fs_config_func = NULL;
+	int gzip = 0;
+	int sparse = 0;
+	int crc = 0;
+	int wipe = 0;
+	int fd;
+	int exitcode;
+	int verbose = 0;
+	struct selabel_handle *sehnd = NULL;
+#ifndef USE_MINGW
+	struct selinux_opt seopts[] = { { SELABEL_OPT_PATH, "" } };
+#endif
+
+	while ((opt = getopt(argc, argv, "l:j:b:g:i:I:L:a:S:fwzJsctv")) != -1) {
+		switch (opt) {
+		case 'l':
+			info.len = parse_num(optarg);
+			break;
+		case 'j':
+			info.journal_blocks = parse_num(optarg);
+			break;
+		case 'b':
+			info.block_size = parse_num(optarg);
+			break;
+		case 'g':
+			info.blocks_per_group = parse_num(optarg);
+			break;
+		case 'i':
+			info.inodes = parse_num(optarg);
+			break;
+		case 'I':
+			info.inode_size = parse_num(optarg);
+			break;
+		case 'L':
+			info.label = optarg;
+			break;
+		case 'f':
+			force = 1;
+			break;
+		case 'a':
+#ifdef ANDROID
+			fs_config_func = fs_config;
+			mountpoint = optarg;
+#else
+			fprintf(stderr, "can't set android permissions - built without android support\n");
+			usage(argv[0]);
+			exit(EXIT_FAILURE);
+#endif
+			break;
+		case 'w':
+			wipe = 1;
+			break;
+		case 'z':
+			gzip = 1;
+			break;
+		case 'J':
+			info.no_journal = 1;
+			break;
+		case 'c':
+			crc = 1;
+			break;
+		case 's':
+			sparse = 1;
+			break;
+		case 't':
+			fprintf(stderr, "Warning: -t (initialize inode tables) is deprecated\n");
+			break;
+		case 'S':
+#ifndef USE_MINGW
+			seopts[0].value = optarg;
+			sehnd = selabel_open(SELABEL_CTX_FILE, seopts, 1);
+			if (!sehnd) {
+				perror(optarg);
+				exit(EXIT_FAILURE);
+			}
+#endif
+			break;
+		case 'v':
+			verbose = 1;
+			break;
+		default: /* '?' */
+			usage(argv[0]);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+#if !defined(HOST)
+	// Use only if -S option not requested
+	if (!sehnd && mountpoint) {
+		sehnd = selinux_android_file_context_handle();
+
+		if (!sehnd) {
+			perror(optarg);
+			exit(EXIT_FAILURE);
+		}
+	}
+#endif
+
+	if (wipe && sparse) {
+		fprintf(stderr, "Cannot specifiy both wipe and sparse\n");
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (wipe && gzip) {
+		fprintf(stderr, "Cannot specifiy both wipe and gzip\n");
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (optind >= argc) {
+		fprintf(stderr, "Expected filename after options\n");
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	filename = argv[optind++];
+
+	if (optind < argc)
+		directory = argv[optind++];
+
+	if (optind < argc) {
+		fprintf(stderr, "Unexpected argument: %s\n", argv[optind]);
+		usage(argv[0]);
+		exit(EXIT_FAILURE);
+	}
+
+	if (strcmp(filename, "-")) {
+		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
+		if (fd < 0) {
+			perror("open");
+			return EXIT_FAILURE;
+		}
+	} else {
+		fd = STDOUT_FILENO;
+	}
+
+	exitcode = make_ext4fs_internal(fd, directory, mountpoint, fs_config_func, gzip,
+			sparse, crc, wipe, sehnd, verbose);
+	close(fd);
+	if (exitcode && strcmp(filename, "-"))
+		unlink(filename);
+	return exitcode;
+}
diff --git a/distrib/ext4_utils/src/mkuserimg.sh b/distrib/ext4_utils/src/mkuserimg.sh
new file mode 100755
index 0000000..c44129e
--- /dev/null
+++ b/distrib/ext4_utils/src/mkuserimg.sh
@@ -0,0 +1,61 @@
+#!/bin/bash -x
+#
+# To call this script, make sure make_ext4fs is somewhere in PATH
+
+function usage() {
+cat<<EOT
+Usage:
+mkuserimg.sh [-s] SRC_DIR OUTPUT_FILE EXT_VARIANT MOUNT_POINT SIZE [FILE_CONTEXTS]
+EOT
+}
+
+echo "in mkuserimg.sh PATH=$PATH"
+
+ENABLE_SPARSE_IMAGE=
+if [ "$1" = "-s" ]; then
+  ENABLE_SPARSE_IMAGE="-s"
+  shift
+fi
+
+if [ $# -ne 5 -a $# -ne 6 ]; then
+  usage
+  exit 1
+fi
+
+SRC_DIR=$1
+if [ ! -d $SRC_DIR ]; then
+  echo "Can not find directory $SRC_DIR!"
+  exit 2
+fi
+
+OUTPUT_FILE=$2
+EXT_VARIANT=$3
+MOUNT_POINT=$4
+SIZE=$5
+FC=$6
+
+case $EXT_VARIANT in
+  ext4) ;;
+  *) echo "Only ext4 is supported!"; exit 3 ;;
+esac
+
+if [ -z $MOUNT_POINT ]; then
+  echo "Mount point is required"
+  exit 2
+fi
+
+if [ -z $SIZE ]; then
+  echo "Need size of filesystem"
+  exit 2
+fi
+
+if [ -n "$FC" ]; then
+    FCOPT="-S $FC"
+fi
+
+MAKE_EXT4FS_CMD="make_ext4fs $ENABLE_SPARSE_IMAGE $FCOPT -l $SIZE -a $MOUNT_POINT $OUTPUT_FILE $SRC_DIR"
+echo $MAKE_EXT4FS_CMD
+$MAKE_EXT4FS_CMD
+if [ $? -ne 0 ]; then
+  exit 4
+fi
diff --git a/distrib/ext4_utils/src/setup_fs.c b/distrib/ext4_utils/src/setup_fs.c
new file mode 100644
index 0000000..56c563f
--- /dev/null
+++ b/distrib/ext4_utils/src/setup_fs.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/reboot.h>
+#include <sys/wait.h>
+#include <cutils/android_reboot.h>
+#include <cutils/partition_utils.h>
+
+const char *mkfs = "/system/bin/make_ext4fs";
+
+int setup_fs(const char *blockdev)
+{
+    char buf[256], path[128];
+    pid_t child;
+    int status, n;
+    pid_t pid;
+
+        /* we might be looking at an indirect reference */
+    n = readlink(blockdev, path, sizeof(path) - 1);
+    if (n > 0) {
+        path[n] = 0;
+        if (!memcmp(path, "/dev/block/", 11))
+            blockdev = path + 11;
+    }
+
+    if (strchr(blockdev,'/')) {
+        fprintf(stderr,"not a block device name: %s\n", blockdev);
+        return 0;
+    }
+
+    snprintf(buf, sizeof(buf), "/sys/fs/ext4/%s", blockdev);
+    if (access(buf, F_OK) == 0) {
+        fprintf(stderr,"device %s already has a filesystem\n", blockdev);
+        return 0;
+    }
+    snprintf(buf, sizeof(buf), "/dev/block/%s", blockdev);
+
+    if (!partition_wiped(buf)) {
+        fprintf(stderr,"device %s not wiped, probably encrypted, not wiping\n", blockdev);
+        return 0;
+    }
+
+    fprintf(stderr,"+++\n");
+
+    child = fork();
+    if (child < 0) {
+        fprintf(stderr,"error: setup_fs: fork failed\n");
+        return 0;
+    }
+    if (child == 0) {
+        execl(mkfs, mkfs, buf, NULL);
+        exit(-1);
+    }
+
+    while ((pid=waitpid(-1, &status, 0)) != child) {
+        if (pid == -1) {
+            fprintf(stderr, "error: setup_fs: waitpid failed!\n");
+            return 1;
+        }
+    }
+
+    fprintf(stderr,"---\n");
+    return 1;
+}
+
+
+int main(int argc, char **argv)
+{
+    int need_reboot = 0;
+
+    while (argc > 1) {
+        if (strlen(argv[1]) < 128)
+            need_reboot |= setup_fs(argv[1]);
+        argv++;
+        argc--;
+    }
+
+    if (need_reboot) {
+        fprintf(stderr,"REBOOT!\n");
+        android_reboot(ANDROID_RB_RESTART, 0, 0);
+        exit(-1);
+    }
+    return 0;
+}
diff --git a/distrib/ext4_utils/src/sha1.c b/distrib/ext4_utils/src/sha1.c
new file mode 100644
index 0000000..463ec38
--- /dev/null
+++ b/distrib/ext4_utils/src/sha1.c
@@ -0,0 +1,273 @@
+/*	$NetBSD: sha1.c,v 1.1 2005/12/20 20:29:40 christos Exp $	*/
+/*	$OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $	*/
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ *
+ * Test Vectors (from FIPS PUB 180-1)
+ * "abc"
+ *   A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+ * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ *   84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+ * A million repetitions of "a"
+ *   34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+ */
+
+#define SHA1HANDSOFF		/* Copies data before messing with it. */
+
+#ifndef USE_MINGW
+#include <sys/cdefs.h>
+#endif
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+
+#include "sha1.h"
+
+#if HAVE_NBTOOL_CONFIG_H
+#include "nbtool_config.h"
+#endif
+
+#if !HAVE_SHA1_H
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/*
+ * blk0() and blk() perform the initial expand.
+ * I got the idea of expanding during the round function from SSLeay
+ */
+#if BYTE_ORDER == LITTLE_ENDIAN
+# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
+    |(rol(block->l[i],8)&0x00FF00FF))
+#else
+# define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
+    ^block->l[(i+2)&15]^block->l[i&15],1))
+
+/*
+ * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1
+ */
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+typedef union {
+    u_char c[64];
+    u_int l[16];
+} CHAR64LONG16;
+
+/* old sparc64 gcc could not compile this */
+#undef SPARC64_GCC_WORKAROUND
+#if defined(__sparc64__) && defined(__GNUC__) && __GNUC__ < 3
+#define SPARC64_GCC_WORKAROUND
+#endif
+
+#ifdef SPARC64_GCC_WORKAROUND
+void do_R01(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *);
+void do_R2(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *);
+void do_R3(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *);
+void do_R4(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *);
+
+#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i)
+#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i)
+#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i)
+#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i)
+#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i)
+
+void
+do_R01(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *block)
+{
+    nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2); nR0(c,d,e,a,b, 3);
+    nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5); nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7);
+    nR0(c,d,e,a,b, 8); nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11);
+    nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14); nR0(a,b,c,d,e,15);
+    nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17); nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19);
+}
+
+void
+do_R2(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *block)
+{
+    nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22); nR2(c,d,e,a,b,23);
+    nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25); nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27);
+    nR2(c,d,e,a,b,28); nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31);
+    nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34); nR2(a,b,c,d,e,35);
+    nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37); nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39);
+}
+
+void
+do_R3(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *block)
+{
+    nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42); nR3(c,d,e,a,b,43);
+    nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45); nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47);
+    nR3(c,d,e,a,b,48); nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51);
+    nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54); nR3(a,b,c,d,e,55);
+    nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57); nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59);
+}
+
+void
+do_R4(u_int32_t *a, u_int32_t *b, u_int32_t *c, u_int32_t *d, u_int32_t *e, CHAR64LONG16 *block)
+{
+    nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62); nR4(c,d,e,a,b,63);
+    nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65); nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67);
+    nR4(c,d,e,a,b,68); nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71);
+    nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74); nR4(a,b,c,d,e,75);
+    nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77); nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79);
+}
+#endif
+
+/*
+ * Hash a single 512-bit block. This is the core of the algorithm.
+ */
+void SHA1Transform(state, buffer)
+    u_int32_t state[5];
+    const u_char buffer[64];
+{
+    u_int32_t a, b, c, d, e;
+    CHAR64LONG16 *block;
+
+#ifdef SHA1HANDSOFF
+    CHAR64LONG16 workspace;
+#endif
+
+    assert(buffer != 0);
+    assert(state != 0);
+
+#ifdef SHA1HANDSOFF
+    block = &workspace;
+    (void)memcpy(block, buffer, 64);
+#else
+    block = (CHAR64LONG16 *)(void *)buffer;
+#endif
+
+    /* Copy context->state[] to working vars */
+    a = state[0];
+    b = state[1];
+    c = state[2];
+    d = state[3];
+    e = state[4];
+
+#ifdef SPARC64_GCC_WORKAROUND
+    do_R01(&a, &b, &c, &d, &e, block);
+    do_R2(&a, &b, &c, &d, &e, block);
+    do_R3(&a, &b, &c, &d, &e, block);
+    do_R4(&a, &b, &c, &d, &e, block);
+#else
+    /* 4 rounds of 20 operations each. Loop unrolled. */
+    R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+    R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+    R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+    R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+    R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+    R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+    R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+    R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+    R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+    R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+    R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+    R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+    R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+    R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+    R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+    R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+    R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+    R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+    R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+    R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+#endif
+
+    /* Add the working vars back into context.state[] */
+    state[0] += a;
+    state[1] += b;
+    state[2] += c;
+    state[3] += d;
+    state[4] += e;
+
+    /* Wipe variables */
+    a = b = c = d = e = 0;
+}
+
+
+/*
+ * SHA1Init - Initialize new context
+ */
+void SHA1Init(context)
+    SHA1_CTX *context;
+{
+
+    assert(context != 0);
+
+    /* SHA1 initialization constants */
+    context->state[0] = 0x67452301;
+    context->state[1] = 0xEFCDAB89;
+    context->state[2] = 0x98BADCFE;
+    context->state[3] = 0x10325476;
+    context->state[4] = 0xC3D2E1F0;
+    context->count[0] = context->count[1] = 0;
+}
+
+
+/*
+ * Run your data through this.
+ */
+void SHA1Update(context, data, len)
+    SHA1_CTX *context;
+    const u_char *data;
+    u_int len;
+{
+    u_int i, j;
+
+    assert(context != 0);
+    assert(data != 0);
+
+    j = context->count[0];
+    if ((context->count[0] += len << 3) < j)
+	context->count[1] += (len>>29)+1;
+    j = (j >> 3) & 63;
+    if ((j + len) > 63) {
+	(void)memcpy(&context->buffer[j], data, (i = 64-j));
+	SHA1Transform(context->state, context->buffer);
+	for ( ; i + 63 < len; i += 64)
+	    SHA1Transform(context->state, &data[i]);
+	j = 0;
+    } else {
+	i = 0;
+    }
+    (void)memcpy(&context->buffer[j], &data[i], len - i);
+}
+
+
+/*
+ * Add padding and return the message digest.
+ */
+void SHA1Final(digest, context)
+    u_char digest[20];
+    SHA1_CTX* context;
+{
+    u_int i;
+    u_char finalcount[8];
+
+    assert(digest != 0);
+    assert(context != 0);
+
+    for (i = 0; i < 8; i++) {
+	finalcount[i] = (u_char)((context->count[(i >= 4 ? 0 : 1)]
+	 >> ((3-(i & 3)) * 8) ) & 255);	 /* Endian independent */
+    }
+    SHA1Update(context, (const u_char *)"\200", 1);
+    while ((context->count[0] & 504) != 448)
+	SHA1Update(context, (const u_char *)"\0", 1);
+    SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform() */
+
+    if (digest) {
+	for (i = 0; i < 20; i++)
+	    digest[i] = (u_char)
+		((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255);
+    }
+}
+
+#endif /* HAVE_SHA1_H */
diff --git a/distrib/ext4_utils/src/sha1.h b/distrib/ext4_utils/src/sha1.h
new file mode 100644
index 0000000..9a8f7e3
--- /dev/null
+++ b/distrib/ext4_utils/src/sha1.h
@@ -0,0 +1,43 @@
+/*	$NetBSD: sha1.h,v 1.13 2005/12/26 18:41:36 perry Exp $	*/
+
+/*
+ * SHA-1 in C
+ * By Steve Reid <steve@edmweb.com>
+ * 100% Public Domain
+ */
+
+#ifndef _SYS_SHA1_H_
+#define	_SYS_SHA1_H_
+
+#include <sys/types.h>
+#include <stdint.h>
+
+#ifdef USE_MINGW
+typedef unsigned char u_char;
+typedef unsigned int uint32_t;
+typedef unsigned int u_int32_t;
+typedef unsigned int u_int;
+
+#define __BEGIN_DECLS
+#define __END_DECLS
+#else
+#include <sys/cdefs.h>
+#endif
+
+#define SHA1_DIGEST_LENGTH		20
+#define SHA1_DIGEST_STRING_LENGTH	41
+
+typedef struct {
+	uint32_t state[5];
+	uint32_t count[2];
+	u_char buffer[64];
+} SHA1_CTX;
+
+__BEGIN_DECLS
+void	SHA1Transform(uint32_t[5], const u_char[64]);
+void	SHA1Init(SHA1_CTX *);
+void	SHA1Update(SHA1_CTX *, const u_char *, u_int);
+void	SHA1Final(u_char[SHA1_DIGEST_LENGTH], SHA1_CTX *);
+__END_DECLS
+
+#endif /* _SYS_SHA1_H_ */
diff --git a/distrib/ext4_utils/src/test_ext4fixup b/distrib/ext4_utils/src/test_ext4fixup
new file mode 100755
index 0000000..a920a59
--- /dev/null
+++ b/distrib/ext4_utils/src/test_ext4fixup
@@ -0,0 +1,71 @@
+#!/bin/bash
+
+typeset -i I ITERATIONS PHASE LOC COUNT MAXCOUNT
+
+ME=`basename $0`
+
+if [ "$#" -ne 3 ]
+then
+  echo "$ME: Usage: $ME <iterations> <maxcount> <filesystem_image>" >&2
+  exit 1;
+fi
+
+ITERATIONS="$1"
+MAXCOUNT="$2"
+ORIG_FS_IMAGE="$3"
+FIXED_FS_IMAGE="/tmp/fixedfsimage.$$"
+NEW_FS_IMAGE="/tmp/newfsimage.$$"
+
+if [ ! -f "$ORIG_FS_IMAGE" ]
+then
+  echo "$ME: Filesystem image $NEW_FS_IMAGE does not exist" >&2
+  exit 1
+fi
+
+trap "rm -f $NEW_FS_IMAGE $FIXED_FS_IMAGE" 0 1 2 3 15
+
+rm -f "$NEW_FS_IMAGE" "$FIXED_FS_IMAGE"
+
+# Create the fixed image to compare against
+cp "$ORIG_FS_IMAGE" "$FIXED_FS_IMAGE"
+ext4fixup "$FIXED_FS_IMAGE"
+
+if [ "$?" -ne 0 ]
+then
+  echo "$ME: ext4fixup failed!\n"
+  exit 1
+fi
+
+I=0
+while [ "$I" -lt "$ITERATIONS" ]
+do
+  # There is also a phase 4, which is writing out the updated superblocks and
+  # block group descriptors.  Test the with a separate script.
+  let PHASE="$RANDOM"%3         # 0 to 2
+  let PHASE++                   # 1 to 3
+  let LOC="$RANDOM"%2           # 0 to 1
+  let LOC++                     # 1 to 2
+  let COUNT="$RANDOM"%"$MAXCOUNT"
+
+  # Make a copy of the original image to fixup
+  cp "$ORIG_FS_IMAGE" "$NEW_FS_IMAGE"
+
+  # Run the fixup tool, but die partway through to see if we can recover
+  ext4fixup -d "$PHASE,$LOC,$COUNT" "$NEW_FS_IMAGE" 2>/dev/null
+ 
+  # run it again without -d to have it finish the job
+  ext4fixup "$NEW_FS_IMAGE"
+
+  if cmp "$FIXED_FS_IMAGE" "$NEW_FS_IMAGE"
+  then
+    :
+  else
+    echo "$ME: test failed with parameters $PHASE, $LOC, $COUNT"
+    exit 1
+  fi
+
+  rm -f "$NEW_FS_IMAGE"
+
+  let I++
+done
+
diff --git a/distrib/ext4_utils/src/uuid.c b/distrib/ext4_utils/src/uuid.c
new file mode 100644
index 0000000..33d2494
--- /dev/null
+++ b/distrib/ext4_utils/src/uuid.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 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 <string.h>
+
+#ifdef USE_MINGW
+#include <winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+#include "ext4_utils.h"
+#include "sha1.h"
+#include "uuid.h"
+
+/* Definition from RFC-4122 */
+struct uuid {
+	u32 time_low;
+	u16 time_mid;
+	u16 time_hi_and_version;
+	u8 clk_seq_hi_res;
+	u8 clk_seq_low;
+	u16 node0_1;
+	u32 node2_5;
+};
+
+static void sha1_hash(const char *namespace, const char *name,
+	unsigned char sha1[SHA1_DIGEST_LENGTH])
+{
+	SHA1_CTX ctx;
+	SHA1Init(&ctx);
+	SHA1Update(&ctx, (const u8*)namespace, strlen(namespace));
+	SHA1Update(&ctx, (const u8*)name, strlen(name));
+	SHA1Final(sha1, &ctx);
+}
+
+void generate_uuid(const char *namespace, const char *name, u8 result[16])
+{
+	unsigned char sha1[SHA1_DIGEST_LENGTH];
+	struct uuid *uuid = (struct uuid *)result;
+
+	sha1_hash(namespace, name, (unsigned char*)sha1);
+	memcpy(uuid, sha1, sizeof(struct uuid));
+
+	uuid->time_low = ntohl(uuid->time_low);
+	uuid->time_mid = ntohs(uuid->time_mid);
+	uuid->time_hi_and_version = ntohs(uuid->time_hi_and_version);
+	uuid->time_hi_and_version &= 0x0FFF;
+	uuid->time_hi_and_version |= (5 << 12);
+	uuid->clk_seq_hi_res &= ~(1 << 6);
+	uuid->clk_seq_hi_res |= 1 << 7;
+}
diff --git a/distrib/ext4_utils/src/uuid.h b/distrib/ext4_utils/src/uuid.h
new file mode 100644
index 0000000..ff1b438
--- /dev/null
+++ b/distrib/ext4_utils/src/uuid.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _UUID_H_
+#define _UUID_H_
+
+#include "ext4_utils.h"
+
+void generate_uuid(const char *namespace, const char *name, u8 result[16]);
+
+#endif
diff --git a/distrib/ext4_utils/src/wipe.c b/distrib/ext4_utils/src/wipe.c
new file mode 100644
index 0000000..5766632
--- /dev/null
+++ b/distrib/ext4_utils/src/wipe.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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 "ext4_utils.h"
+#include "wipe.h"
+
+#if WIPE_IS_SUPPORTED
+
+#if defined(__linux__)
+
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+
+#ifndef BLKDISCARD
+#define BLKDISCARD _IO(0x12,119)
+#endif
+
+#ifndef BLKSECDISCARD
+#define BLKSECDISCARD _IO(0x12,125)
+#endif
+
+int wipe_block_device(int fd, s64 len)
+{
+	u64 range[2];
+	int ret;
+
+	if (!is_block_device_fd(fd)) {
+		// Wiping only makes sense on a block device.
+		return 0;
+	}
+
+	range[0] = 0;
+	range[1] = len;
+	ret = ioctl(fd, BLKSECDISCARD, &range);
+	if (ret < 0) {
+		range[0] = 0;
+		range[1] = len;
+		ret = ioctl(fd, BLKDISCARD, &range);
+		if (ret < 0) {
+			warn("Discard failed\n");
+			return 1;
+		} else {
+			warn("Wipe via secure discard failed, used discard instead\n");
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+#else  /* __linux__ */
+#error "Missing block device wiping implementation for this platform!"
+#endif
+
+#else  /* WIPE_IS_SUPPORTED */
+
+int wipe_block_device(int fd, s64 len)
+{
+	/* Wiping is not supported on this platform. */
+	return 1;
+}
+
+#endif  /* WIPE_IS_SUPPORTED */
diff --git a/distrib/ext4_utils/src/wipe.h b/distrib/ext4_utils/src/wipe.h
new file mode 100644
index 0000000..bd119e3
--- /dev/null
+++ b/distrib/ext4_utils/src/wipe.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2010 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.
+ */
+
+#ifndef _WIPE_H_
+#define _WIPE_H_
+
+#include "ext4_utils.h"
+
+/* Set WIPE_IS_SUPPORTED to 1 if the current platform supports
+ * wiping of block devices. 0 otherwise. For now, only Linux does.
+ */
+#ifdef __linux__
+#  define WIPE_IS_SUPPORTED 1
+#else
+#  define WIPE_IS_SUPPORTED 0
+#endif
+
+int wipe_block_device(int fd, s64 len);
+
+#endif
diff --git a/distrib/ext4_utils/src/xattr.h b/distrib/ext4_utils/src/xattr.h
new file mode 100644
index 0000000..0f323fd
--- /dev/null
+++ b/distrib/ext4_utils/src/xattr.h
@@ -0,0 +1,45 @@
+#include <sys/types.h>
+
+#ifndef _SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H
+#define _SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H 1
+
+#define EXT4_XATTR_MAGIC 0xEA020000
+#define EXT4_XATTR_INDEX_SECURITY 6
+
+struct ext4_xattr_header {
+    __le32  h_magic;
+    __le32  h_refcount;
+    __le32  h_blocks;
+    __le32  h_hash;
+    __le32  h_checksum;
+    __u32   h_reserved[3];
+};
+
+struct ext4_xattr_ibody_header {
+    __le32  h_magic;
+};
+
+struct ext4_xattr_entry {
+    __u8 e_name_len;
+    __u8 e_name_index;
+    __le16 e_value_offs;
+    __le32 e_value_block;
+    __le32 e_value_size;
+    __le32 e_hash;
+    char e_name[0];
+};
+
+#define EXT4_XATTR_PAD_BITS 2
+#define EXT4_XATTR_PAD (1<<EXT4_XATTR_PAD_BITS)
+#define EXT4_XATTR_ROUND (EXT4_XATTR_PAD-1)
+#define EXT4_XATTR_LEN(name_len) \
+    (((name_len) + EXT4_XATTR_ROUND + \
+    sizeof(struct ext4_xattr_entry)) & ~EXT4_XATTR_ROUND)
+#define EXT4_XATTR_NEXT(entry) \
+    ((struct ext4_xattr_entry *)( \
+     (char *)(entry) + EXT4_XATTR_LEN((entry)->e_name_len)))
+#define EXT4_XATTR_SIZE(size) \
+    (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND)
+#define IS_LAST_ENTRY(entry) (*(uint32_t *)(entry) == 0)
+
+#endif /* !_SYSTEM_EXTRAS_EXT4_UTILS_XATTR_H */