Merge changes I7352dc43,Icc1c3225,Idd0e4950,I5b709c56,Ia12bbb4d, ...

* changes:
  vl-android.c: Support EXT4 cache partitions.
  android/filesystems/partition_types.h: new header
  Support EXT4 cache partition images.
  Add android_createEmptyExt4Image()
  distrib/ext4_utils: new third-party library sources.
  distrib/libselinux: Add new third-party library sources.
  distrib/libsparse: Add new third-party library sources.
  distrib/zlib-1.2.8: Build as static libraries.
diff --git a/Makefile.android b/Makefile.android
index 1694e66..350b72f 100644
--- a/Makefile.android
+++ b/Makefile.android
@@ -334,6 +334,12 @@
   endif
 endif
 
+# Build libext4_utils and related modules/
+include $(LOCAL_PATH)/distrib/zlib-1.2.8/sources.make
+include $(LOCAL_PATH)/distrib/libsparse/sources.mk
+include $(LOCAL_PATH)/distrib/libselinux/sources.mk
+include $(LOCAL_PATH)/distrib/ext4_utils/sources.mk
+
 include $(LOCAL_PATH)/Makefile.common
 
 ifeq ($(HOST_OS),windows)
diff --git a/Makefile.common b/Makefile.common
index 2a077bf..17f886e 100644
--- a/Makefile.common
+++ b/Makefile.common
@@ -88,11 +88,7 @@
 ###########################################################
 # Zlib sources
 #
-ZLIB_DIR := distrib/zlib-1.2.8
-include $(LOCAL_PATH)/$(ZLIB_DIR)/sources.make
-EMULATOR_COMMON_CFLAGS += -I$(LOCAL_PATH)/$(ZLIB_DIR)
-
-common_LOCAL_SRC_FILES += $(ZLIB_SOURCES)
+EMULATOR_COMMON_CFLAGS += -I$(ZLIB_INCLUDES)
 
 ###########################################################
 # GLib sources
@@ -127,6 +123,7 @@
 	android/base/StringView.cpp \
 	android/emulation/CpuAccelerator.cpp \
 	android/filesystems/ext4_utils.cpp \
+	android/filesystems/partition_types.cpp \
 	android/kernel/kernel_utils.cpp \
 	android/utils/assert.c \
 	android/utils/bufprint.c \
@@ -155,6 +152,7 @@
 
 common_LOCAL_CFLAGS += $(EMULATOR_COMMON_CFLAGS)
 
+common_LOCAL_CFLAGS += -I$(LIBEXT4_UTILS_INCLUDES)
 
 ## one for 32-bit
 $(call start-emulator-library, emulator-common)
diff --git a/Makefile.target b/Makefile.target
index 0feb1e7..ae5e1cd 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -299,7 +299,8 @@
     emulator-libqemu \
     emulator-target-$(EMULATOR_TARGET_CPU) \
     emulator-libelff \
-    emulator-common
+    emulator-common \
+    emulator-zlib
 
 common_LOCAL_LDLIBS += \
     $(EMULATOR_COMMON_LDLIBS) \
@@ -363,7 +364,12 @@
     emulator-libjpeg \
     emulator-libelff \
     emulator-common \
+    emulator-libext4_utils \
+    emulator-libsparse \
+    emulator-libselinux \
+    emulator-zlib \
     $(SDL_STATIC_LIBRARIES)
+
 LOCAL_LDLIBS += $(common_LOCAL_LDLIBS)
 LOCAL_LDFLAGS += $(common_LOCAL_LDFLAGS)
 LOCAL_CFLAGS += $(common_LOCAL_CFLAGS)
@@ -398,7 +404,12 @@
     emulator64-libjpeg \
     emulator64-libelff \
     emulator64-common \
+    emulator64-libext4_utils \
+    emulator64-libsparse \
+    emulator64-libselinux \
+    emulator64-zlib \
     $(SDL_STATIC_LIBRARIES_64)
+
 LOCAL_LDLIBS += $(common_LOCAL_LDLIBS)
 LOCAL_CFLAGS += $(common_LOCAL_CFLAGS)
 LOCAL_SRC_FILES += $(common_LOCAL_SRC_FILES)
diff --git a/Makefile.tests b/Makefile.tests
index 5ff4c56..b9a5a28 100644
--- a/Makefile.tests
+++ b/Makefile.tests
@@ -23,6 +23,8 @@
   android/base/StringView_unittest.cpp \
   android/emulation/CpuAccelerator_unittest.cpp \
   android/filesystems/ext4_utils_unittest.cpp \
+  android/filesystems/partition_types_unittest.cpp \
+  android/filesystems/testing/TestSupport.cpp \
   android/kernel/kernel_utils_unittest.cpp \
 
 ifeq (windows,$(HOST_OS))
@@ -36,7 +38,13 @@
 LOCAL_LDLIBS += $(EMULATOR_GTEST_LDLIBS)
 LOCAL_SRC_FILES := $(EMULATOR_UNITTESTS_SOURCES)
 LOCAL_CFLAGS += -O0
-LOCAL_STATIC_LIBRARIES += emulator-common emulator-libgtest
+LOCAL_STATIC_LIBRARIES += \
+    emulator-common \
+    emulator-libext4_utils \
+    emulator-libsparse \
+    emulator-libselinux \
+    emulator-zlib \
+    emulator-libgtest
 $(call end-emulator-program)
 
 
@@ -45,5 +53,11 @@
 LOCAL_LDLIBS += $(EMULATOR_GTEST_LDLIBS)
 LOCAL_SRC_FILES := $(EMULATOR_UNITTESTS_SOURCES)
 LOCAL_CFLAGS += -O0
-LOCAL_STATIC_LIBRARIES += emulator64-common emulator64-libgtest
+LOCAL_STATIC_LIBRARIES += \
+    emulator64-common \
+    emulator64-libext4_utils \
+    emulator64-libsparse \
+    emulator64-libselinux \
+    emulator64-zlib \
+    emulator64-libgtest
 $(call end-emulator-program)
diff --git a/android/avd/hardware-properties.ini b/android/avd/hardware-properties.ini
index 327b75d..ad9d2a6 100644
--- a/android/avd/hardware-properties.ini
+++ b/android/avd/hardware-properties.ini
@@ -306,7 +306,14 @@
 enum        = autodetect, yes, no
 default     = autodetect
 abstract    = Does the kernel require a new device naming scheme?
-abstract    = Used to specify whether the kernel requires a new device naming scheme. Typically for Linux 3.10 and above.
+description = Used to specify whether the kernel requires a new device naming scheme. Typically for Linux 3.10 and above.
+
+name        = kernel.supportsYaffs2
+type        = string
+enum        = autodetect, yes, no
+default     = autodetect
+abstract    = Does the kernel supports YAFFS2 partitions?
+description = Used to specify whether the kernel supports YAFFS2 partition images. Typically before 3.10 only.
 
 # Path to the ramdisk image.
 name        = disk.ramdisk.path
diff --git a/android/avd/hw-config.c b/android/avd/hw-config.c
index 34f2ed4..0650c54 100644
--- a/android/avd/hw-config.c
+++ b/android/avd/hw-config.c
@@ -154,6 +154,16 @@
     return -1;
 }
 
+int
+androidHwConfig_getKernelYaffs2Support( AndroidHwConfig* config )
+{
+    if (!strcmp(config->kernel_supportsYaffs2, "no"))
+        return 0;
+    if (!strcmp(config->kernel_supportsYaffs2, "yes"))
+        return 1;
+    return -1;
+}
+
 const char* androidHwConfig_getKernelSerialPrefix(AndroidHwConfig* config )
 {
     if (androidHwConfig_getKernelDeviceNaming(config) >= 1) {
diff --git a/android/avd/hw-config.h b/android/avd/hw-config.h
index 81444fb..82a3a5e 100644
--- a/android/avd/hw-config.h
+++ b/android/avd/hw-config.h
@@ -75,6 +75,13 @@
 // declarations in android/kernel/kernel_utils.h
 int androidHwConfig_getKernelDeviceNaming( AndroidHwConfig* config );
 
+// Return an integer indicating is the kernel supports YAFFS2 partition
+// images. More specifically:
+//  -1 -> don't know, caller will need to auto-detect.
+//   0 -> does not support YAFFS2 partitions.
+//   1 -> does support YAFFS2 partitions.
+int androidHwConfig_getKernelYaffs2Support( AndroidHwConfig* config );
+
 // Return the kernel device prefix for serial ports, depending on
 // kernel.newDeviceNaming.
 const char* androidHwConfig_getKernelSerialPrefix( AndroidHwConfig* config );
diff --git a/android/filesystems/ext4_utils.cpp b/android/filesystems/ext4_utils.cpp
index 5d60c57..2c10646 100644
--- a/android/filesystems/ext4_utils.cpp
+++ b/android/filesystems/ext4_utils.cpp
@@ -14,6 +14,8 @@
 #include "android/base/Log.h"
 #include "android/base/files/ScopedStdioFile.h"
 
+#include "make_ext4fs.h"
+
 #include <stdint.h>
 #include <string.h>
 
@@ -65,3 +67,12 @@
     EXT4_LOG << "Not an Ext4 partition image: " << path;
     return false;
 }
+
+int android_createEmptyExt4Image(const char *filePath,
+                                 uint64_t size,
+                                 const char *mountpoint) {
+    int ret = ::make_ext4fs(filePath, size, mountpoint, NULL);
+    if (ret < 0)
+        EXT4_ERROR << "Failed to create ext4 image at: " << filePath;
+    return ret;
+}
diff --git a/android/filesystems/ext4_utils.h b/android/filesystems/ext4_utils.h
index e8dad10..e6db2f3 100644
--- a/android/filesystems/ext4_utils.h
+++ b/android/filesystems/ext4_utils.h
@@ -15,9 +15,18 @@
 #include "android/utils/compiler.h"
 
 #include <stdbool.h>
+#include <inttypes.h>
 
 ANDROID_BEGIN_HEADER
 
+// Create a new empty EXT4 partition image file at |filePath|
+// of |size| bytes. |mountPoint| is the name of the corresponding
+// mount point, e.g. 'cache' for the cache partition.
+// Returns 0 on success, or -errno on failure.
+int android_createEmptyExt4Image(const char *filePath,
+                                 uint64_t size,
+                                 const char *mountpoint);
+
 // Returns true iff the file at |filePath| is an actual EXT4 partition image.
 bool android_pathIsExt4PartitionImage(const char* filePath);
 
diff --git a/android/filesystems/ext4_utils_unittest.cpp b/android/filesystems/ext4_utils_unittest.cpp
index 94c6e57..66cc4a7 100644
--- a/android/filesystems/ext4_utils_unittest.cpp
+++ b/android/filesystems/ext4_utils_unittest.cpp
@@ -14,6 +14,8 @@
 #include "android/base/EintrWrapper.h"
 #include "android/base/Log.h"
 #include "android/base/files/ScopedStdioFile.h"
+#include "android/filesystems/testing/TestExt4ImageHeader.h"
+#include "android/filesystems/testing/TestSupport.h"
 
 #include <gtest/gtest.h>
 
@@ -28,144 +30,13 @@
 #endif
 
 using android::base::ScopedStdioFile;
-
-// These are the first 1082 bytes of an EXT4 system.img file
-// It was generated with:
-//
-//    dd -if=$SDK/system-images/android-19/armeabi-v7a/system.img
-//       -of=/tmp/ext4-system.img
-//       -bs=1082 -count=1
-//
-//    xxd -i /tmp/ext4-system.img
-//
-// The two last bytes must be 0x53 / 0xef, i.e. the EXT4 magic bytes.
-//
-static const unsigned char kExt4SystemImage[] = {
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x80, 0x89, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x15, 0x19, 0x01, 0x00, 0xd6, 0x85, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x1b, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
-  0x53, 0xef
-};
-
-static const size_t kExt4SystemImageSize = sizeof(kExt4SystemImage);
-
-
-// TODO(digit): Move that to a test-support class.
-static std::string createTempFilePath() {
-#ifdef _WIN32
-    char tempDir[MAX_PATH];
-    DWORD ret = GetTempPath(MAX_PATH, tempDir);
-    CHECK(ret > 0 && ret < MAX_PATH)
-            << "Could not get temporary directory path";
-
-    std::string result;
-    result.resize(MAX_PATH);
-    UINT ret2 = GetTempFileName(tempDir, "emulator-test-", 0,  &result[0]);
-    CHECK(ret2 != ERROR_BUFFER_OVERFLOW) << "Could not create temporary file name";
-    result.resize(::strlen(result.c_str()));
-    return result;
-#else
-    std::string result("/tmp/emulator-test.XXXXXX");
-    int ret = HANDLE_EINTR(mkstemp(&result[0]));
-    PCHECK(ret >= 0) << "Could not create temporary filepath";
-    ::close(ret);
-    return result;
-#endif
-}
-
+using android::testing::CreateTempFilePath;
 
 class Ext4UtilsTest : public ::testing::Test {
 public:
     Ext4UtilsTest() : mTempFilePath() {
         ::memset(mImage, 0, sizeof mImage);
-        ::memcpy(mImage, kExt4SystemImage, kExt4SystemImageSize);
+        ::memcpy(mImage, kTestExt4ImageHeader, kTestExt4ImageHeaderSize);
     }
 
     ~Ext4UtilsTest() {
@@ -181,7 +52,7 @@
     const char* createTempFile(size_t maxBytes) {
         CHECK(maxBytes <= sizeof mImage);
         // TODO(digit): Replace with something else.
-        mTempFilePath = createTempFilePath();
+        mTempFilePath = CreateTempFilePath();
         ScopedStdioFile file(fopen(mTempFilePath.c_str(), "wb"));
         PCHECK(file.get()) << "Could not create temporary file!";
         PCHECK(::fwrite(mImage, maxBytes, 1, file.get()) == 1)
@@ -191,17 +62,24 @@
         return mTempFilePath.c_str();
     }
 
+    // Create the path of a temporary file, but do not create or
+    // populate it. The file is removed in the destructor.
+    const char* createTempPath() {
+        mTempFilePath = CreateTempFilePath();
+        return mTempFilePath.c_str();
+    }
+
     std::string mTempFilePath;
-    char mImage[kExt4SystemImageSize * 2U];
+    char mImage[kTestExt4ImageHeaderSize * 2U];
 };
 
 TEST_F(Ext4UtilsTest, android_pathIsExt4PartitionImage) {
-    const char* path = createTempFile(kExt4SystemImageSize);
+    const char* path = createTempFile(kTestExt4ImageHeaderSize);
     EXPECT_TRUE(android_pathIsExt4PartitionImage(path));
 }
 
 TEST_F(Ext4UtilsTest, android_pathIsExt4PartitionImageTruncated) {
-    const char* path = createTempFile(kExt4SystemImageSize - 2U);
+    const char* path = createTempFile(kTestExt4ImageHeaderSize - 2U);
     EXPECT_FALSE(android_pathIsExt4PartitionImage(path));
 }
 
@@ -212,13 +90,21 @@
 }
 
 TEST_F(Ext4UtilsTest, android_pathIsExt4PartitionImageBadMagic1) {
-    mImage[kExt4SystemImageSize - 1] = 0;
+    mImage[kTestExt4ImageHeaderSize - 1] = 0;
     const char* path = createTempFile(sizeof mImage);
     EXPECT_FALSE(android_pathIsExt4PartitionImage(path));
 }
 
 TEST_F(Ext4UtilsTest, android_pathIsExt4PartitionImageBadMagic2) {
-    mImage[kExt4SystemImageSize - 2] = 0;
+    mImage[kTestExt4ImageHeaderSize - 2] = 0;
     const char* path = createTempFile(sizeof mImage);
     EXPECT_FALSE(android_pathIsExt4PartitionImage(path));
 }
+
+TEST_F(Ext4UtilsTest, android_createEmptyExt4Partition) {
+    const char* tempPath = createTempPath();
+    uint64_t kSize = 32 * 1024 * 1024;
+    int ret = android_createEmptyExt4Image(tempPath, kSize, "cache");
+    EXPECT_EQ(0, ret);
+    EXPECT_TRUE(android_pathIsExt4PartitionImage(tempPath));
+}
diff --git a/android/filesystems/partition_types.cpp b/android/filesystems/partition_types.cpp
new file mode 100644
index 0000000..f0dfba7
--- /dev/null
+++ b/android/filesystems/partition_types.cpp
@@ -0,0 +1,65 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/filesystems/partition_types.h"
+
+#include "android/filesystems/ext4_utils.h"
+#include "android/utils/panic.h"
+#include "android/utils/path.h"
+
+#include <errno.h>
+
+const char* androidPartitionType_toString(AndroidPartitionType part_type) {
+    switch (part_type) {
+        case ANDROID_PARTITION_TYPE_UNKNOWN:
+            return "unknown";
+        case ANDROID_PARTITION_TYPE_YAFFS2:
+            return "yaffs2";
+        case ANDROID_PARTITION_TYPE_EXT4:
+            return "ext4";
+        default:
+            APANIC("Invalid partition type value %d", part_type);
+    }
+}
+
+
+AndroidPartitionType androidPartitionType_probeFile(const char* image_file) {
+    if (!path_exists(image_file)) {
+        return ANDROID_PARTITION_TYPE_UNKNOWN;
+    }
+    if (android_pathIsExt4PartitionImage(image_file)) {
+        return ANDROID_PARTITION_TYPE_EXT4;
+    }
+    // Assume YAFFS2, since there is little way to be sure for now.
+    // NOTE: An empty file is a valid Yaffs2 file!
+    return ANDROID_PARTITION_TYPE_YAFFS2;
+}
+
+
+int androidPartitionType_makeEmptyFile(AndroidPartitionType part_type,
+                                       uint64_t part_size,
+                                       const char* part_file) {
+    switch (part_type) {
+        case ANDROID_PARTITION_TYPE_YAFFS2:
+            // Any empty file is a valid YAFFS2 partition, |part_size|
+            // can be ignored here.
+            if (path_empty_file(part_file) < 0) {
+                return -errno;
+            }
+            return 0;
+
+        case ANDROID_PARTITION_TYPE_EXT4:
+            return android_createEmptyExt4Image(part_file, part_size, NULL);
+
+        default:
+            return -EINVAL;
+    }
+}
diff --git a/android/filesystems/partition_types.h b/android/filesystems/partition_types.h
new file mode 100644
index 0000000..9bbdcf4
--- /dev/null
+++ b/android/filesystems/partition_types.h
@@ -0,0 +1,46 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_FILESYSTEMS_PARTITION_TYPES_H
+#define ANDROID_FILESYSTEMS_PARTITION_TYPES_H
+
+#include "android/utils/compiler.h"
+
+#include <inttypes.h>
+
+ANDROID_BEGIN_HEADER
+
+// List of supported Android partition image types.
+typedef enum {
+    ANDROID_PARTITION_TYPE_UNKNOWN = 0,
+    ANDROID_PARTITION_TYPE_YAFFS2 = 1,
+    ANDROID_PARTITION_TYPE_EXT4 = 2,
+} AndroidPartitionType;
+
+// Return a string describing the partition type to the caller.
+// Note: this will panic if |part_type| is an invalid value.
+const char* androidPartitionType_toString(AndroidPartitionType part_type);
+
+// Probe a given image file and return its partition image type.
+// Note: this returns ANDROID_PARTITION_TYPE_UNKNOWN if the file does
+// not exist or cannot be read.
+AndroidPartitionType androidPartitionType_probeFile(const char* image_file);
+
+// Create or reset the file at |image_file| to be an empty partition of type
+// |part_type| and size |part_size|. Returns 0 on success, or -errno on
+// failure.
+int androidPartitionType_makeEmptyFile(AndroidPartitionType part_type,
+                                       uint64_t part_size,
+                                       const char* image_file);
+
+ANDROID_END_HEADER
+
+#endif  // ANDROID_FILESYSTEMS_PARTITION_TYPES_H
diff --git a/android/filesystems/partition_types_unittest.cpp b/android/filesystems/partition_types_unittest.cpp
new file mode 100644
index 0000000..5bdddd9
--- /dev/null
+++ b/android/filesystems/partition_types_unittest.cpp
@@ -0,0 +1,102 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/filesystems/partition_types.h"
+
+#include "android/base/EintrWrapper.h"
+#include "android/base/files/ScopedStdioFile.h"
+#include "android/filesystems/ext4_utils.h"
+#include "android/filesystems/testing/TestExt4ImageHeader.h"
+#include "android/filesystems/testing/TestSupport.h"
+
+#include "android/utils/path.h"
+
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <string>
+#include <unistd.h>
+
+namespace {
+
+using android::base::ScopedStdioFile;
+
+class TempPartition {
+public:
+    TempPartition() {
+        mPath = android::testing::CreateTempFilePath();
+    }
+
+    ~TempPartition() {
+        if (!mPath.empty()) {
+            HANDLE_EINTR(::unlink(mPath.c_str()));
+        }
+    }
+
+    const char* GetPath() const {
+        return mPath.c_str();
+    }
+
+protected:
+    std::string mPath;
+};
+
+}  // namespace
+
+TEST(AndroidPartitionType, ToString) {
+    EXPECT_STREQ("unknown", androidPartitionType_toString(ANDROID_PARTITION_TYPE_UNKNOWN));
+    EXPECT_STREQ("yaffs2", androidPartitionType_toString(ANDROID_PARTITION_TYPE_YAFFS2));
+    EXPECT_STREQ("ext4", androidPartitionType_toString(ANDROID_PARTITION_TYPE_EXT4));
+}
+
+TEST(AndroidPartitionType, ProbeFileYaffs2) {
+    TempPartition part;
+
+    // An empty partition is a valid YAFFS2 one.
+    ::path_empty_file(part.GetPath());
+
+    EXPECT_EQ(ANDROID_PARTITION_TYPE_YAFFS2,
+              androidPartitionType_probeFile(part.GetPath()));
+}
+
+
+TEST(AndroidPartitionType, ProbeFileExt4) {
+    TempPartition part;
+
+    android_createEmptyExt4Image(part.GetPath(), 16*1024*1024, "cache");
+
+    EXPECT_EQ(ANDROID_PARTITION_TYPE_EXT4,
+              androidPartitionType_probeFile(part.GetPath()));
+}
+
+TEST(AndroidPartitionType, MakeEmptyFileYaffs2) {
+    TempPartition part;
+
+    EXPECT_EQ(0, androidPartitionType_makeEmptyFile(
+            ANDROID_PARTITION_TYPE_YAFFS2,
+            8 * 1024 * 1024,
+            part.GetPath())) << "Could not create Yaffs2 partition image";
+
+    EXPECT_EQ(ANDROID_PARTITION_TYPE_YAFFS2,
+              androidPartitionType_probeFile(part.GetPath()));
+}
+
+TEST(AndroidPartitionType, MakeEmptyFileExt4) {
+    TempPartition part;
+
+    EXPECT_EQ(0, androidPartitionType_makeEmptyFile(
+            ANDROID_PARTITION_TYPE_EXT4,
+            8 * 1024 * 1024,
+            part.GetPath())) << "Could not create EXT4 partition image";
+
+    EXPECT_EQ(ANDROID_PARTITION_TYPE_EXT4,
+              androidPartitionType_probeFile(part.GetPath()));
+}
diff --git a/android/filesystems/testing/TestExt4ImageHeader.h b/android/filesystems/testing/TestExt4ImageHeader.h
new file mode 100644
index 0000000..13d41e2
--- /dev/null
+++ b/android/filesystems/testing/TestExt4ImageHeader.h
@@ -0,0 +1,122 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_FILESYSTEMS_TESTING_TEST_EXT4_IMAGE_HEADER_H
+#define ANDROID_FILESYSTEMS_TESTING_TEST_EXT4_IMAGE_HEADER_H
+
+// These are the first 1082 bytes of an EXT4 system.img file
+// It was generated with:
+//
+//    dd -if=$SDK/system-images/android-19/armeabi-v7a/system.img
+//       -of=/tmp/ext4-system.img
+//       -bs=1082 -count=1
+//
+//    xxd -i /tmp/ext4-system.img
+//
+// The two last bytes must be 0x53 / 0xef, i.e. the EXT4 magic bytes.
+//
+static const unsigned char kTestExt4ImageHeader[] = {
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x80, 0x89, 0x00, 0x00, 0x00, 0x26, 0x02, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x15, 0x19, 0x01, 0x00, 0xd6, 0x85, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x1b, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
+  0x53, 0xef
+};
+
+static const size_t kTestExt4ImageHeaderSize = sizeof(kTestExt4ImageHeader);
+
+#endif  // ANDROID_FILESYSTEMS_TESTING_TEST_EXT4_IMAGE_HEADER_H
diff --git a/android/filesystems/testing/TestSupport.cpp b/android/filesystems/testing/TestSupport.cpp
new file mode 100644
index 0000000..f084306
--- /dev/null
+++ b/android/filesystems/testing/TestSupport.cpp
@@ -0,0 +1,49 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#include "android/filesystems/testing/TestSupport.h"
+
+#include "android/base/EintrWrapper.h"
+#include "android/base/Log.h"
+
+#include <stdlib.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace android {
+namespace testing {
+
+std::string CreateTempFilePath() {
+#ifdef _WIN32
+    char tempDir[MAX_PATH];
+    DWORD ret = GetTempPath(MAX_PATH, tempDir);
+    CHECK(ret > 0 && ret < MAX_PATH)
+            << "Could not get temporary directory path";
+
+    std::string result;
+    result.resize(MAX_PATH);
+    UINT ret2 = GetTempFileName(tempDir, "emulator-test-", 0,  &result[0]);
+    CHECK(ret2 != ERROR_BUFFER_OVERFLOW) << "Could not create temporary file name";
+    result.resize(::strlen(result.c_str()));
+    return result;
+#else
+    std::string result("/tmp/emulator-test.XXXXXX");
+    int ret = HANDLE_EINTR(mkstemp(&result[0]));
+    PCHECK(ret >= 0) << "Could not create temporary filepath";
+    ::close(ret);
+    return result;
+#endif
+}
+
+}  // namespace testing
+}  // namespace android
diff --git a/android/filesystems/testing/TestSupport.h b/android/filesystems/testing/TestSupport.h
new file mode 100644
index 0000000..b2285b5
--- /dev/null
+++ b/android/filesystems/testing/TestSupport.h
@@ -0,0 +1,25 @@
+// Copyright 2014 The Android Open Source Project
+//
+// This software is licensed under the terms of the GNU General Public
+// License version 2, as published by the Free Software Foundation, and
+// may be copied, distributed, and modified under those terms.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+#ifndef ANDROID_FILESYSTEMS_TESTING_TEST_SUPPORT_H
+#define ANDROID_FILESYSTEMS_TESTING_TEST_SUPPORT_H
+
+#include <string>
+
+namespace android {
+namespace testing {
+
+std::string CreateTempFilePath();
+
+}  // namespace testing
+}  // namespace android
+
+#endif  // ANDROID_FILESYSTEMS_TESTING_TEST_SUPPORT_H
diff --git a/android/main.c b/android/main.c
index c01fa92..363c923 100644
--- a/android/main.c
+++ b/android/main.c
@@ -454,15 +454,17 @@
          }
     }
 
+    KernelType kernelType = KERNEL_TYPE_LEGACY;
+    if (!android_pathProbeKernelType(hw->kernel_path, &kernelType)) {
+        D("WARNING: Could not determine kernel device naming scheme. Assuming legacy\n"
+            "If this AVD doesn't boot, and uses a recent kernel (3.10 or above) try setting\n"
+            "'kernel.newDeviceNaming' to 'yes' in its configuration.\n");
+    }
+
     // Auto-detect kernel device naming scheme if needed.
     if (androidHwConfig_getKernelDeviceNaming(hw) < 0) {
-        KernelType kernelType;
         const char* newDeviceNaming = "no";
-        if (!android_pathProbeKernelType(hw->kernel_path, &kernelType)) {
-            D("WARNING: Could not determine kernel device naming scheme. Assuming legacy\n"
-              "If this AVD doesn't boot, and uses a recent kernel (3.10 or above) try setting\n"
-              "'kernel.newDeviceNaming' to 'yes' in its configuration.\n");
-        } else if (kernelType == KERNEL_TYPE_3_10_OR_ABOVE) {
+        if (kernelType == KERNEL_TYPE_3_10_OR_ABOVE) {
             D("Auto-detect: Kernel image requires new device naming scheme.");
             newDeviceNaming = "yes";
         } else {
@@ -472,6 +474,19 @@
         hw->kernel_newDeviceNaming = ASTRDUP(newDeviceNaming);
     }
 
+    // Auto-detect YAFFS2 partition support if needed.
+    if (androidHwConfig_getKernelYaffs2Support(hw) < 0) {
+        const char* newYaffs2Support = "no";
+        if (kernelType == KERNEL_TYPE_3_10_OR_ABOVE) {
+            D("Auto-detect: Kernel does not support YAFFS2 partitions.");
+        } else {
+            D("Auto-detect: Kernel does support YAFFS2 partitions.");
+            newYaffs2Support = "yes";
+        }
+        AFREE(hw->kernel_supportsYaffs2);
+        hw->kernel_supportsYaffs2 = ASTRDUP(newYaffs2Support);
+    }
+
     if (boot_prop_ip[0]) {
         args[n++] = "-boot-property";
         args[n++] = boot_prop_ip;
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 */
diff --git a/distrib/libselinux/NOTICE b/distrib/libselinux/NOTICE
new file mode 100644
index 0000000..d386268
--- /dev/null
+++ b/distrib/libselinux/NOTICE
@@ -0,0 +1,21 @@
+This library (libselinux) is public domain software, i.e. not copyrighted.
+
+Warranty Exclusion
+------------------
+You agree that this software is a
+non-commercially developed program that may contain "bugs" (as that
+term is used in the industry) and that it may not function as intended.
+The software is licensed "as is". NSA makes no, and hereby expressly
+disclaims all, warranties, express, implied, statutory, or otherwise
+with respect to the software, including noninfringement and the implied
+warranties of merchantability and fitness for a particular purpose.
+
+Limitation of Liability
+-----------------------
+In no event will NSA be liable for any damages, including loss of data,
+lost profits, cost of cover, or other special, incidental,
+consequential, direct or indirect damages arising from the software or
+the use thereof, however caused and on any theory of liability. This
+limitation will apply even if NSA has been advised of the possibility
+of such damage. You acknowledge that this is a reasonable allocation of
+risk.
diff --git a/distrib/libselinux/README b/distrib/libselinux/README
new file mode 100644
index 0000000..44e96f0
--- /dev/null
+++ b/distrib/libselinux/README
@@ -0,0 +1,4 @@
+This directory contains the content of $AOSP/external/libselinux taken
+from the following commit:
+
+    e9b58950df18f55a74e3b79bffe7f18556613ad1
diff --git a/distrib/libselinux/include/selinux/android.h b/distrib/libselinux/include/selinux/android.h
new file mode 100644
index 0000000..ae6c05d
--- /dev/null
+++ b/distrib/libselinux/include/selinux/android.h
@@ -0,0 +1,51 @@
+#ifndef _SELINUX_ANDROID_H_
+#define _SELINUX_ANDROID_H_
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <selinux/label.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct selabel_handle* selinux_android_file_context_handle(void);
+
+extern void selinux_android_set_sehandle(const struct selabel_handle *hndl);
+
+extern int selinux_android_load_policy(void);
+
+extern int selinux_android_reload_policy(void);
+
+extern int selinux_android_setcontext(uid_t uid,
+				      int isSystemServer,
+				      const char *seinfo,
+				      const char *name);
+
+extern int selinux_android_setfilecon(const char *pkgdir,
+				       const char *pkgname,
+				       const char *seinfo,
+				       uid_t uid);
+
+#define SELINUX_ANDROID_RESTORECON_NOCHANGE 1
+#define SELINUX_ANDROID_RESTORECON_VERBOSE  2
+#define SELINUX_ANDROID_RESTORECON_RECURSE  4
+#define SELINUX_ANDROID_RESTORECON_FORCE    8
+#define SELINUX_ANDROID_RESTORECON_DATADATA 16
+extern int selinux_android_restorecon(const char *file, unsigned int flags);
+
+extern int selinux_android_restorecon_pkgdir(const char *pkgdir,
+                                             const char *seinfo,
+                                             uid_t uid,
+                                             unsigned int flags);
+
+extern int selinux_android_seapp_context_reload(void);
+
+extern bool selinux_android_use_data_policy(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/distrib/libselinux/include/selinux/avc.h b/distrib/libselinux/include/selinux/avc.h
new file mode 100644
index 0000000..8a1a6df
--- /dev/null
+++ b/distrib/libselinux/include/selinux/avc.h
@@ -0,0 +1,507 @@
+/*
+ * Access vector cache interface for object managers.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+#ifndef _SELINUX_AVC_H_
+#define _SELINUX_AVC_H_
+
+#include <stdint.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <selinux/selinux.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * SID format and operations
+ */
+struct security_id {
+	char * ctx;
+	unsigned int refcnt;
+};
+typedef struct security_id *security_id_t;
+
+#define SECSID_WILD (security_id_t)NULL	/* unspecified SID */
+
+/**
+ * avc_sid_to_context - get copy of context corresponding to SID.
+ * @sid: input SID
+ * @ctx: pointer to context reference
+ *
+ * Return a copy of the security context corresponding to the input
+ * @sid in the memory referenced by @ctx.  The caller is expected to 
+ * free the context with freecon().  Return %0 on success, -%1 on
+ * failure, with @errno set to %ENOMEM if insufficient memory was
+ * available to make the copy, or %EINVAL if the input SID is invalid.
+ */
+int avc_sid_to_context(security_id_t sid, char ** ctx);
+int avc_sid_to_context_raw(security_id_t sid, char ** ctx);
+
+/**
+ * avc_context_to_sid - get SID for context.
+ * @ctx: input security context
+ * @sid: pointer to SID reference
+ *
+ * Look up security context @ctx in SID table, making
+ * a new entry if @ctx is not found.  Increment the
+ * reference counter for the SID.  Store a pointer
+ * to the SID structure into the memory referenced by @sid, 
+ * returning %0 on success or -%1 on error with @errno set.  
+ */
+int avc_context_to_sid(const char * ctx, security_id_t * sid);
+int avc_context_to_sid_raw(const char * ctx, security_id_t * sid);
+
+/**
+ * sidget - increment SID reference counter.
+ * @sid: SID reference
+ *
+ * Increment the reference counter for @sid, indicating that
+ * @sid is in use by an (additional) object.  Return the
+ * new reference count, or zero if @sid is invalid (has zero
+ * reference count).  Note that avc_context_to_sid() also
+ * increments reference counts.
+ */
+int sidget(security_id_t sid);
+
+/**
+ * sidput - decrement SID reference counter.
+ * @sid: SID reference
+ *
+ * Decrement the reference counter for @sid, indicating that
+ * a reference to @sid is no longer in use.  Return the 
+ * new reference count.  When the reference count reaches
+ * zero, the SID is invalid, and avc_context_to_sid() must
+ * be called to obtain a new SID for the security context.
+ */
+int sidput(security_id_t sid);
+
+/**
+ * avc_get_initial_sid - get SID for an initial kernel security identifier
+ * @name: input name of initial kernel security identifier
+ * @sid: pointer to a SID reference
+ *
+ * Get the context for an initial kernel security identifier specified by 
+ * @name using security_get_initial_context() and then call 
+ * avc_context_to_sid() to get the corresponding SID.
+ */
+int avc_get_initial_sid(const char *name, security_id_t * sid);
+
+/*
+ * AVC entry
+ */
+struct avc_entry;
+struct avc_entry_ref {
+	struct avc_entry *ae;
+};
+
+/**
+ * avc_entry_ref_init - initialize an AVC entry reference.
+ * @aeref: pointer to avc entry reference structure
+ *
+ * Use this macro to initialize an avc entry reference structure
+ * before first use.  These structures are passed to avc_has_perm(),
+ * which stores cache entry references in them.  They can increase
+ * performance on repeated queries.
+ */
+#define avc_entry_ref_init(aeref) ((aeref)->ae = NULL)
+
+/*
+ * User-provided callbacks for memory, auditing, and locking
+ */
+
+/* These structures are passed by reference to avc_init().  Passing
+ * a NULL reference will cause the AVC to use a default.  The default
+ * memory callbacks are malloc() and free().  The default logging method
+ * is to print on stderr.  If no thread callbacks are passed, a separate
+ * listening thread won't be started for kernel policy change messages.
+ * If no locking callbacks are passed, no locking will take place.
+ */
+struct avc_memory_callback {
+	/* malloc() equivalent. */
+	void *(*func_malloc) (size_t size);
+	/* free() equivalent. */
+	void (*func_free) (void *ptr);
+	/* Note that these functions should set errno on failure.
+	   If not, some avc routines may return -1 without errno set. */
+};
+
+struct avc_log_callback {
+	/* log the printf-style format and arguments. */
+	void (*func_log) (const char *fmt, ...);
+	/* store a string representation of auditdata (corresponding
+	   to the given security class) into msgbuf. */
+	void (*func_audit) (void *auditdata, security_class_t cls,
+			    char *msgbuf, size_t msgbufsize);
+};
+
+struct avc_thread_callback {
+	/* create and start a thread, returning an opaque pointer to it; 
+	   the thread should run the given function. */
+	void *(*func_create_thread) (void (*run) (void));
+	/* cancel a given thread and free its resources. */
+	void (*func_stop_thread) (void *thread);
+};
+
+struct avc_lock_callback {
+	/* create a lock and return an opaque pointer to it. */
+	void *(*func_alloc_lock) (void);
+	/* obtain a given lock, blocking if necessary. */
+	void (*func_get_lock) (void *lock);
+	/* release a given lock. */
+	void (*func_release_lock) (void *lock);
+	/* destroy a given lock (free memory, etc.) */
+	void (*func_free_lock) (void *lock);
+};
+
+/*
+ * Available options
+ */
+
+/* no-op option, useful for unused slots in an array of options */
+#define AVC_OPT_UNUSED		0
+/* override kernel enforcing mode (boolean value) */
+#define AVC_OPT_SETENFORCE	1
+
+/*
+ * AVC operations
+ */
+
+/**
+ * avc_init - Initialize the AVC.
+ * @msgprefix: prefix for log messages
+ * @mem_callbacks: user-supplied memory callbacks
+ * @log_callbacks: user-supplied logging callbacks
+ * @thread_callbacks: user-supplied threading callbacks
+ * @lock_callbacks: user-supplied locking callbacks
+ *
+ * Initialize the access vector cache.  Return %0 on
+ * success or -%1 with @errno set on failure.  
+ * If @msgprefix is NULL, use "uavc".  If any callback 
+ * structure references are NULL, use default methods 
+ * for those callbacks (see the definition of the callback
+ * structures above).
+ */
+int avc_init(const char *msgprefix,
+	     const struct avc_memory_callback *mem_callbacks,
+	     const struct avc_log_callback *log_callbacks,
+	     const struct avc_thread_callback *thread_callbacks,
+	     const struct avc_lock_callback *lock_callbacks);
+
+/**
+ * avc_open - Initialize the AVC.
+ * @opts: array of selabel_opt structures specifying AVC options or NULL.
+ * @nopts: number of elements in opts array or zero for no options.
+ *
+ * This function is identical to avc_init(), except the message prefix
+ * is set to "avc" and any callbacks desired should be specified via
+ * selinux_set_callback().  Available options are listed above.
+ */
+int avc_open(struct selinux_opt *opts, unsigned nopts);
+
+/**
+ * avc_cleanup - Remove unused SIDs and AVC entries.
+ *
+ * Search the SID table for SID structures with zero
+ * reference counts, and remove them along with all
+ * AVC entries that reference them.  This can be used
+ * to return memory to the system.
+ */
+void avc_cleanup(void);
+
+/**
+ * avc_reset - Flush the cache and reset statistics.
+ *
+ * Remove all entries from the cache and reset all access
+ * statistics (as returned by avc_cache_stats()) to zero.
+ * The SID mapping is not affected.  Return %0 on success, 
+ * -%1 with @errno set on error.
+ */
+int avc_reset(void);
+
+/**
+ * avc_destroy - Free all AVC structures.
+ *
+ * Destroy all AVC structures and free all allocated
+ * memory.  User-supplied locking, memory, and audit
+ * callbacks will be retained, but security-event
+ * callbacks will not.  All SID's will be invalidated.
+ * User must call avc_init() if further use of AVC is desired.
+ */
+void avc_destroy(void);
+
+/**
+ * avc_has_perm_noaudit - Check permissions but perform no auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref:  AVC entry reference
+ * @avd: access vector decisions
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Update @aeref to refer to an AVC
+ * entry with the resulting decisions, and return a copy of the decisions
+ * in @avd.  Return %0 if all @requested permissions are granted, -%1 with
+ * @errno set to %EACCES if any permissions are denied, or to another value
+ * upon other errors.  This function is typically called by avc_has_perm(),
+ * but may also be called directly to separate permission checking from
+ * auditing, e.g. in cases where a lock must be held for the check but
+ * should be released for the auditing.
+ */
+int avc_has_perm_noaudit(security_id_t ssid,
+			 security_id_t tsid,
+			 security_class_t tclass,
+			 access_vector_t requested,
+			 struct avc_entry_ref *aeref, struct av_decision *avd);
+
+/**
+ * avc_has_perm - Check permissions and perform any appropriate auditing.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref:  AVC entry reference
+ * @auditdata: auxiliary audit data
+ *
+ * Check the AVC to determine whether the @requested permissions are granted
+ * for the SID pair (@ssid, @tsid), interpreting the permissions
+ * based on @tclass, and call the security server on a cache miss to obtain
+ * a new decision and add it to the cache.  Update @aeref to refer to an AVC
+ * entry with the resulting decisions.  Audit the granting or denial of
+ * permissions in accordance with the policy.  Return %0 if all @requested
+ * permissions are granted, -%1 with @errno set to %EACCES if any permissions
+ * are denied or to another value upon other errors.
+ */
+int avc_has_perm(security_id_t ssid, security_id_t tsid,
+		 security_class_t tclass, access_vector_t requested,
+		 struct avc_entry_ref *aeref, void *auditdata);
+
+/**
+ * avc_audit - Audit the granting or denial of permissions.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions
+ * @avd: access vector decisions
+ * @result: result from avc_has_perm_noaudit
+ * @auditdata:  auxiliary audit data
+ *
+ * Audit the granting or denial of permissions in accordance
+ * with the policy.  This function is typically called by
+ * avc_has_perm() after a permission check, but can also be
+ * called directly by callers who use avc_has_perm_noaudit()
+ * in order to separate the permission check from the auditing.
+ * For example, this separation is useful when the permission check must
+ * be performed under a lock, to allow the lock to be released
+ * before calling the auditing code.
+ */
+void avc_audit(security_id_t ssid, security_id_t tsid,
+	       security_class_t tclass, access_vector_t requested,
+	       struct av_decision *avd, int result, void *auditdata);
+
+/**
+ * avc_compute_create - Compute SID for labeling a new object.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @newsid: pointer to SID reference
+ *
+ * Call the security server to obtain a context for labeling a
+ * new object.  Look up the context in the SID table, making
+ * a new entry if not found.  Increment the reference counter
+ * for the SID.  Store a pointer to the SID structure into the
+ * memory referenced by @newsid, returning %0 on success or -%1 on
+ * error with @errno set.  
+ */
+int avc_compute_create(security_id_t ssid,
+		       security_id_t tsid,
+		       security_class_t tclass, security_id_t * newsid);
+
+/**
+ * avc_compute_member - Compute SID for polyinstantation.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @newsid: pointer to SID reference
+ *
+ * Call the security server to obtain a context for labeling an
+ * object instance.  Look up the context in the SID table, making
+ * a new entry if not found.  Increment the reference counter
+ * for the SID.  Store a pointer to the SID structure into the
+ * memory referenced by @newsid, returning %0 on success or -%1 on
+ * error with @errno set.  
+ */
+int avc_compute_member(security_id_t ssid,
+		       security_id_t tsid,
+		       security_class_t tclass, security_id_t * newsid);
+
+/* 
+ * security event callback facility
+ */
+
+/* security events */
+#define AVC_CALLBACK_GRANT		1
+#define AVC_CALLBACK_TRY_REVOKE		2
+#define AVC_CALLBACK_REVOKE		4
+#define AVC_CALLBACK_RESET		8
+#define AVC_CALLBACK_AUDITALLOW_ENABLE	16
+#define AVC_CALLBACK_AUDITALLOW_DISABLE	32
+#define AVC_CALLBACK_AUDITDENY_ENABLE	64
+#define AVC_CALLBACK_AUDITDENY_DISABLE	128
+
+/**
+ * avc_add_callback - Register a callback for security events.
+ * @callback: callback function
+ * @events: bitwise OR of desired security events
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions
+ *
+ * Register a callback function for events in the set @events
+ * related to the SID pair (@ssid, @tsid) and
+ * and the permissions @perms, interpreting
+ * @perms based on @tclass.  Returns %0 on success or
+ * -%1 if insufficient memory exists to add the callback.
+ */
+int avc_add_callback(int (*callback)
+		      (uint32_t event, security_id_t ssid,
+		       security_id_t tsid, security_class_t tclass,
+		       access_vector_t perms,
+		       access_vector_t * out_retained),
+		     uint32_t events, security_id_t ssid,
+		     security_id_t tsid, security_class_t tclass,
+		     access_vector_t perms);
+
+/*
+ * AVC statistics 
+ */
+
+/* If set, cache statistics are tracked.  This may
+ * become a compile-time option in the future.
+ */
+#define AVC_CACHE_STATS     1
+
+struct avc_cache_stats {
+	unsigned entry_lookups;
+	unsigned entry_hits;
+	unsigned entry_misses;
+	unsigned entry_discards;
+	unsigned cav_lookups;
+	unsigned cav_hits;
+	unsigned cav_probes;
+	unsigned cav_misses;
+};
+
+/**
+ * avc_cache_stats - get cache access statistics.
+ * @stats: reference to statistics structure
+ *
+ * Fill the supplied structure with information about AVC 
+ * activity since the last call to avc_init() or
+ * avc_reset().  See the structure definition for
+ * details.
+ */
+void avc_cache_stats(struct avc_cache_stats *stats);
+
+/**
+ * avc_av_stats - log av table statistics.
+ *
+ * Log a message with information about the size and
+ * distribution of the access vector table.  The audit
+ * callback is used to print the message.
+ */
+void avc_av_stats(void);
+
+/**
+ * avc_sid_stats - log SID table statistics.
+ *
+ * Log a message with information about the size and
+ * distribution of the SID table.  The audit callback
+ * is used to print the message.
+ */
+void avc_sid_stats(void);
+
+/**
+ * avc_netlink_open - Create a netlink socket and connect to the kernel.
+ */
+int avc_netlink_open(int blocking);
+
+/**
+ * avc_netlink_loop - Wait for netlink messages from the kernel
+ */
+void avc_netlink_loop(void);
+
+/**
+ * avc_netlink_close - Close the netlink socket
+ */
+void avc_netlink_close(void);
+
+/**
+ * avc_netlink_acquire_fd - Acquire netlink socket fd.
+ *
+ * Allows the application to manage messages from the netlink socket in
+ * its own main loop.
+ */
+int avc_netlink_acquire_fd(void);
+
+/**
+ * avc_netlink_release_fd - Release netlink socket fd.
+ *
+ * Returns ownership of the netlink socket to the library.
+ */
+void avc_netlink_release_fd(void);
+
+/**
+ * avc_netlink_check_nb - Check netlink socket for new messages.
+ *
+ * Called by the application when using avc_netlink_acquire_fd() to
+ * process kernel netlink events.
+ */
+int avc_netlink_check_nb(void);
+
+/**
+ * selinux_status_open - Open and map SELinux kernel status page
+ *
+ */
+int selinux_status_open(int fallback);
+
+/**
+ * selinux_status_close - Unmap and close SELinux kernel status page
+ *
+ */
+void selinux_status_close(void);
+
+/**
+ * selinux_status_updated - Inform us whether the kernel status has been updated
+ *
+ */
+int selinux_status_updated(void);
+
+/**
+ * selinux_status_getenforce - Get the enforce flag value
+ *
+ */
+int selinux_status_getenforce(void);
+
+/**
+ * selinux_status_policyload - Get the number of policy reloaded
+ *
+ */
+int selinux_status_policyload(void);
+
+/**
+ * selinux_status_deny_unknown - Get the  behavior for undefined classes/permissions
+ *
+ */
+int selinux_status_deny_unknown(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif				/* _SELINUX_AVC_H_ */
diff --git a/distrib/libselinux/include/selinux/context.h b/distrib/libselinux/include/selinux/context.h
new file mode 100644
index 0000000..949fb1e
--- /dev/null
+++ b/distrib/libselinux/include/selinux/context.h
@@ -0,0 +1,50 @@
+#ifndef _SELINUX_CONTEXT_H_
+#define _SELINUX_CONTEXT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Functions to deal with security contexts in user space.
+ */
+
+	typedef struct {
+		void *ptr;
+	} context_s_t;
+
+	typedef context_s_t *context_t;
+
+/* Return a new context initialized to a context string */
+
+	extern context_t context_new(const char *);
+
+/* 
+ * Return a pointer to the string value of the context_t
+ * Valid until the next call to context_str or context_free 
+ * for the same context_t*
+ */
+
+	extern char *context_str(context_t);
+
+/* Free the storage used by a context */
+	extern void context_free(context_t);
+
+/* Get a pointer to the string value of a context component */
+
+	extern const char *context_type_get(context_t);
+	extern const char *context_range_get(context_t);
+	extern const char *context_role_get(context_t);
+	extern const char *context_user_get(context_t);
+
+/* Set a context component.  Returns nonzero if unsuccessful */
+
+	extern int context_type_set(context_t, const char *);
+	extern int context_range_set(context_t, const char *);
+	extern int context_role_set(context_t, const char *);
+	extern int context_user_set(context_t, const char *);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/distrib/libselinux/include/selinux/label.h b/distrib/libselinux/include/selinux/label.h
new file mode 100644
index 0000000..facfa57
--- /dev/null
+++ b/distrib/libselinux/include/selinux/label.h
@@ -0,0 +1,142 @@
+/*
+ * Labeling interface for userspace object managers and others.
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ */
+#ifndef _SELABEL_H_
+#define _SELABEL_H_
+
+#include <stdbool.h>
+#include <sys/types.h>
+#include <selinux/selinux.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque type used for all label handles.
+ */
+
+struct selabel_handle;
+
+/* 
+ * Available backends.
+ */
+
+/* file contexts */
+#define SELABEL_CTX_FILE	0
+/* media contexts */
+#define SELABEL_CTX_MEDIA	1
+/* x contexts */
+#define SELABEL_CTX_X		2
+/* db objects */
+#define SELABEL_CTX_DB		3
+/* Android property service contexts */
+#define SELABEL_CTX_ANDROID_PROP 4
+
+/*
+ * Available options
+ */
+
+/* no-op option, useful for unused slots in an array of options */
+#define SELABEL_OPT_UNUSED	0
+/* validate contexts before returning them (boolean value) */
+#define SELABEL_OPT_VALIDATE	1
+/* don't use local customizations to backend data (boolean value) */
+#define SELABEL_OPT_BASEONLY	2
+/* specify an alternate path to use when loading backend data */
+#define SELABEL_OPT_PATH	3
+/* select a subset of the search space as an optimization (file backend) */
+#define SELABEL_OPT_SUBSET	4
+/* total number of options */
+#define SELABEL_NOPT		5
+
+/*
+ * Label operations
+ */
+
+/**
+ * selabel_open - Create a labeling handle.
+ * @backend: one of the constants specifying a supported labeling backend.
+ * @opts: array of selabel_opt structures specifying label options or NULL.
+ * @nopts: number of elements in opts array or zero for no options.
+ *
+ * Open a labeling backend for use.  The available backend identifiers are
+ * listed above.  Options may be provided via the opts parameter; available
+ * options are listed above.  Not all options may be supported by every
+ * backend.  Return value is the created handle on success or NULL with
+ * @errno set on failure.
+ */
+struct selabel_handle *selabel_open(unsigned int backend,
+				    const struct selinux_opt *opts,
+				    unsigned nopts);
+
+/**
+ * selabel_close - Close a labeling handle.
+ * @handle: specifies handle to close
+ *
+ * Destroy the specified handle, closing files, freeing allocated memory,
+ * etc.  The handle may not be further used after it has been closed.
+ */
+void selabel_close(struct selabel_handle *handle);
+
+/**
+ * selabel_lookup - Perform labeling lookup operation.
+ * @handle: specifies backend instance to query
+ * @con: returns the appropriate context with which to label the object
+ * @key: string input to lookup operation
+ * @type: numeric input to the lookup operation
+ *
+ * Perform a labeling lookup operation.  Return %0 on success, -%1 with
+ * @errno set on failure.  The key and type arguments are the inputs to the
+ * lookup operation; appropriate values are dictated by the backend in use.
+ * The result is returned in the memory pointed to by @con and must be freed
+ * by the user with freecon().
+ */
+int selabel_lookup(struct selabel_handle *handle, char **con,
+		   const char *key, int type);
+int selabel_lookup_raw(struct selabel_handle *handle, char **con,
+		       const char *key, int type);
+
+bool selabel_partial_match(struct selabel_handle *handle, const char *key);
+
+/**
+ * selabel_stats - log labeling operation statistics.
+ * @handle: specifies backend instance to query
+ *
+ * Log a message with information about the number of queries performed,
+ * number of unused matching entries, or other operational statistics.
+ * Message is backend-specific, some backends may not output a message.
+ */
+void selabel_stats(struct selabel_handle *handle);
+
+/*
+ * Type codes used by specific backends
+ */
+
+/* X backend */
+#define SELABEL_X_PROP		1
+#define SELABEL_X_EXT		2
+#define SELABEL_X_CLIENT	3
+#define SELABEL_X_EVENT		4
+#define SELABEL_X_SELN		5
+#define SELABEL_X_POLYPROP	6
+#define SELABEL_X_POLYSELN	7
+
+/* DB backend */
+#define SELABEL_DB_DATABASE	1
+#define SELABEL_DB_SCHEMA	2
+#define SELABEL_DB_TABLE	3
+#define SELABEL_DB_COLUMN	4
+#define SELABEL_DB_SEQUENCE	5
+#define SELABEL_DB_VIEW		6
+#define SELABEL_DB_PROCEDURE	7
+#define SELABEL_DB_BLOB		8
+#define SELABEL_DB_TUPLE	9
+#define SELABEL_DB_LANGUAGE	10
+
+#ifdef __cplusplus
+}
+#endif
+#endif	/* _SELABEL_H_ */
diff --git a/distrib/libselinux/include/selinux/selinux.h b/distrib/libselinux/include/selinux/selinux.h
new file mode 100644
index 0000000..8827da8
--- /dev/null
+++ b/distrib/libselinux/include/selinux/selinux.h
@@ -0,0 +1,291 @@
+#ifndef _SELINUX_H_
+#define _SELINUX_H_
+
+#include <sys/types.h>
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Return 1 if we are running on a SELinux kernel, or 0 if not or -1 if we get an error. */
+extern int is_selinux_enabled(void);
+/* Return 1 if we are running on a SELinux MLS kernel, or 0 otherwise. */
+extern int is_selinux_mls_enabled(void);
+
+/* No longer used; here for compatibility with legacy callers. */
+typedef char *security_context_t;
+
+/* Free the memory allocated for a context by any of the below get* calls. */
+extern void freecon(char * con);
+
+/* Free the memory allocated for a context array by security_compute_user. */
+extern void freeconary(char ** con);
+
+/* Wrappers for the /proc/pid/attr API. */
+
+/* Get current context, and set *con to refer to it.
+   Caller must free via freecon. */
+extern int getcon(char ** con);
+
+/* Set the current security context to con.  
+   Note that use of this function requires that the entire application
+   be trusted to maintain any desired separation between the old and new 
+   security contexts, unlike exec-based transitions performed via setexeccon.  
+   When possible, decompose your application and use setexeccon()+execve() 
+   instead. Note that the application may lose access to its open descriptors
+   as a result of a setcon() unless policy allows it to use descriptors opened
+   by the old context. */
+extern int setcon(const char * con);
+
+/* Get context of process identified by pid, and 
+   set *con to refer to it.  Caller must free via freecon. */
+extern int getpidcon(pid_t pid, char ** con);
+
+/* Get previous context (prior to last exec), and set *con to refer to it.
+   Caller must free via freecon. */
+extern int getprevcon(char ** con);
+
+/* Get exec context, and set *con to refer to it.
+   Sets *con to NULL if no exec context has been set, i.e. using default.
+   If non-NULL, caller must free via freecon. */
+extern int getexeccon(char ** con);
+
+/* Set exec security context for the next execve. 
+   Call with NULL if you want to reset to the default. */
+extern int setexeccon(const char * con);
+
+/* Get fscreate context, and set *con to refer to it.
+   Sets *con to NULL if no fs create context has been set, i.e. using default.
+   If non-NULL, caller must free via freecon. */
+extern int getfscreatecon(char ** con);
+
+/* Set the fscreate security context for subsequent file creations.
+   Call with NULL if you want to reset to the default. */
+extern int setfscreatecon(const char * context);
+
+/* Get keycreate context, and set *con to refer to it.
+   Sets *con to NULL if no key create context has been set, i.e. using default.
+   If non-NULL, caller must free via freecon. */
+extern int getkeycreatecon(char ** con);
+
+/* Set the keycreate security context for subsequent key creations.
+   Call with NULL if you want to reset to the default. */
+extern int setkeycreatecon(const char * context);
+
+/* Get sockcreate context, and set *con to refer to it.
+   Sets *con to NULL if no socket create context has been set, i.e. using default.
+   If non-NULL, caller must free via freecon. */
+extern int getsockcreatecon(char ** con);
+
+/* Set the sockcreate security context for subsequent socket creations.
+   Call with NULL if you want to reset to the default. */
+extern int setsockcreatecon(const char * context);
+
+/* Wrappers for the xattr API. */
+
+/* Get file context, and set *con to refer to it.
+   Caller must free via freecon. */
+extern int getfilecon(const char *path, char ** con);
+extern int lgetfilecon(const char *path, char ** con);
+extern int fgetfilecon(int fd, char ** con);
+
+/* Set file context */
+extern int setfilecon(const char *path, const char *con);
+extern int lsetfilecon(const char *path, const char *con);
+extern int fsetfilecon(int fd, const char *con);
+
+/* Wrappers for the socket API */
+
+/* Get context of peer socket, and set *con to refer to it.
+   Caller must free via freecon. */
+extern int getpeercon(int fd, char ** con);
+
+/* Wrappers for the selinuxfs (policy) API. */
+
+typedef unsigned int access_vector_t;
+typedef unsigned short security_class_t;
+
+struct av_decision {
+	access_vector_t allowed;
+	access_vector_t decided;
+	access_vector_t auditallow;
+	access_vector_t auditdeny;
+	unsigned int seqno;
+	unsigned int flags;
+};
+
+/* Definitions of av_decision.flags */
+#define SELINUX_AVD_FLAGS_PERMISSIVE	0x0001
+
+/* Structure for passing options, used by AVC and label subsystems */
+struct selinux_opt {
+	int type;
+	const char *value;
+};
+
+/* Callback facilities */
+union selinux_callback {
+	/* log the printf-style format and arguments,
+	   with the type code indicating the type of message */
+	int 
+#ifdef __GNUC__
+__attribute__ ((format(printf, 2, 3)))
+#endif
+	(*func_log) (int type, const char *fmt, ...);
+	/* store a string representation of auditdata (corresponding
+	   to the given security class) into msgbuf. */
+	int (*func_audit) (void *auditdata, security_class_t cls,
+			   char *msgbuf, size_t msgbufsize);
+	/* validate the supplied context, modifying if necessary */
+	int (*func_validate) (char **ctx);
+	/* netlink callback for setenforce message */
+	int (*func_setenforce) (int enforcing);
+	/* netlink callback for policyload message */
+	int (*func_policyload) (int seqno);
+};
+
+#define SELINUX_CB_LOG		0
+#define SELINUX_CB_AUDIT	1
+#define SELINUX_CB_VALIDATE	2
+#define SELINUX_CB_SETENFORCE	3
+#define SELINUX_CB_POLICYLOAD	4
+
+extern union selinux_callback selinux_get_callback(int type);
+extern void selinux_set_callback(int type, union selinux_callback cb);
+
+	/* Logging type codes, passed to the logging callback */
+#define SELINUX_ERROR	        0
+#define SELINUX_WARNING		1
+#define SELINUX_INFO		2
+#define SELINUX_AVC		3
+
+/* Compute an access decision. */
+extern int security_compute_av(const char * scon,
+			       const char * tcon,
+			       security_class_t tclass,
+			       access_vector_t requested,
+			       struct av_decision *avd);
+
+/* Compute a labeling decision and set *newcon to refer to it.
+   Caller must free via freecon. */
+extern int security_compute_create(const char * scon,
+				   const char * tcon,
+				   security_class_t tclass,
+				   char ** newcon);
+
+/* Compute a relabeling decision and set *newcon to refer to it.
+   Caller must free via freecon. */
+extern int security_compute_relabel(const char * scon,
+				    const char * tcon,
+				    security_class_t tclass,
+				    char ** newcon);
+
+/* Compute a polyinstantiation member decision and set *newcon to refer to it.
+   Caller must free via freecon. */
+extern int security_compute_member(const char * scon,
+				   const char * tcon,
+				   security_class_t tclass,
+				   char ** newcon);
+
+/* Compute the set of reachable user contexts and set *con to refer to 
+   the NULL-terminated array of contexts.  Caller must free via freeconary. */
+extern int security_compute_user(const char * scon,
+				 const char *username,
+				 char *** con);
+
+/* Load a policy configuration. */
+extern int security_load_policy(void *data, size_t len);
+
+/* Get the context of an initial kernel security identifier by name.  
+   Caller must free via freecon */
+extern int security_get_initial_context(const char *name,
+					char ** con);
+
+/* Translate boolean strict to name value pair. */
+typedef struct {
+	const char *name;
+	int value;
+} SELboolean;
+/* save a list of booleans in a single transaction.  */
+extern int security_set_boolean_list(size_t boolcnt,
+				     SELboolean * const boollist, int permanent);
+
+/* Check the validity of a security context. */
+extern int security_check_context(const char * con);
+
+/* Canonicalize a security context. */
+extern int security_canonicalize_context(const char * con,
+					 char ** canoncon);
+
+/* Get the enforce flag value. */
+extern int security_getenforce(void);
+
+/* Set the enforce flag value. */
+extern int security_setenforce(int value);
+
+/* Get the behavior for undefined classes/permissions */
+extern int security_deny_unknown(void);
+
+/* Disable SELinux at runtime (must be done prior to initial policy load). */
+extern int security_disable(void);
+
+/* Get the policy version number. */
+extern int security_policyvers(void);
+
+/* Get the boolean names */
+extern int security_get_boolean_names(char ***names, int *len);
+
+/* Get the pending value for the boolean */
+extern int security_get_boolean_pending(const char *name);
+
+/* Get the active value for the boolean */
+extern int security_get_boolean_active(const char *name);
+
+/* Set the pending value for the boolean */
+extern int security_set_boolean(const char *name, int value);
+
+/* Commit the pending values for the booleans */
+extern int security_commit_booleans(void);
+
+/* Userspace class mapping support */
+struct security_class_mapping {
+	const char *name;
+	const char *perms[sizeof(access_vector_t) * 8 + 1];
+};
+
+extern int selinux_set_mapping(struct security_class_mapping *map);
+
+/* Common helpers */
+
+/* Convert between security class values and string names */
+extern security_class_t string_to_security_class(const char *name);
+extern const char *security_class_to_string(security_class_t cls);
+
+/* Convert between individual access vector permissions and string names */
+extern const char *security_av_perm_to_string(security_class_t tclass,
+					      access_vector_t perm);
+extern access_vector_t string_to_av_perm(security_class_t tclass,
+					 const char *name);
+
+/* Returns an access vector in a string representation.  User must free the
+ * returned string via free(). */
+extern int security_av_string(security_class_t tclass,
+			      access_vector_t av, char **result);
+
+/* Check permissions and perform appropriate auditing. */
+extern int selinux_check_access(const char * scon,
+				const char * tcon,
+				const char *tclass,
+				const char *perm, void *aux);
+
+/* Set the path to the selinuxfs mount point explicitly.
+   Normally, this is determined automatically during libselinux 
+   initialization, but this is not always possible, e.g. for /sbin/init
+   which performs the initial mount of selinuxfs. */
+void set_selinuxmnt(const char *mnt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/distrib/libselinux/sources.mk b/distrib/libselinux/sources.mk
new file mode 100644
index 0000000..70e9993
--- /dev/null
+++ b/distrib/libselinux/sources.mk
@@ -0,0 +1,39 @@
+OLD_LOCAL_PATH := $(LOCAL_PATH)
+LOCAL_PATH := $(call my-dir)
+
+LIBSELINUX_SOURCES := \
+    src/callbacks.c \
+    src/check_context.c \
+    src/freecon.c \
+    src/init.c \
+    src/label.c \
+    src/label_file.c \
+    src/label_android_property.c
+
+ifeq ($(HOST_OS),windows)
+    # This code doesn't not build on Windows, so create empty
+    # libraries on this platform, this simplifies the build
+    # configuration.
+    LIBSELINUX_SOURCES :=
+endif
+
+LIBSELINUX_INCLUDES := $(LOCAL_PATH)/include
+
+LIBSELINUX_CFLAGS := -DHOST
+ifeq (darwin,$(HOST_OS))
+    LIBSELINUX_CFLAGS += -DDARWIN
+endif
+
+$(call start-emulator-library,emulator-libselinux)
+LOCAL_SRC_FILES := $(LIBSELINUX_SOURCES)
+LOCAL_C_INCLUDES := $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBSELINUX_CFLAGS)
+$(call end-emulator-library)
+
+$(call start-emulator64-library,emulator64-libselinux)
+LOCAL_SRC_FILES := $(LIBSELINUX_SOURCES)
+LOCAL_C_INCLUDES := $(LIBSELINUX_INCLUDES)
+LOCAL_CFLAGS := $(LIBSELINUX_CFLAGS)
+$(call end-emulator-library)
+
+LOCAL_PATH := $(OLD_LOCAL_PATH)
diff --git a/distrib/libselinux/src/android.c b/distrib/libselinux/src/android.c
new file mode 100644
index 0000000..d0432d4
--- /dev/null
+++ b/distrib/libselinux/src/android.c
@@ -0,0 +1,1376 @@
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <fcntl.h>
+#include <fts.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+#include <selinux/android.h>
+#include <selinux/label.h>
+#include <selinux/avc.h>
+#include <mincrypt/sha.h>
+#include <private/android_filesystem_config.h>
+#include "policy.h"
+#include "callbacks.h"
+#include "selinux_internal.h"
+#include "label_internal.h"
+
+/*
+ * XXX Where should this configuration file be located?
+ * Needs to be accessible by zygote and installd when
+ * setting credentials for app processes and setting permissions
+ * on app data directories.
+ */
+static char const * const seapp_contexts_file[] = {
+	"/seapp_contexts",
+	"/data/security/current/seapp_contexts",
+	NULL };
+
+static const struct selinux_opt seopts[] = {
+	{ SELABEL_OPT_PATH, "/file_contexts" },
+	{ SELABEL_OPT_PATH, "/data/security/current/file_contexts" },
+	{ 0, NULL } };
+
+static const char *const sepolicy_file[] = {
+	"/sepolicy",
+	"/data/security/current/sepolicy",
+	NULL };
+
+enum levelFrom {
+	LEVELFROM_NONE,
+	LEVELFROM_APP,
+	LEVELFROM_USER,
+	LEVELFROM_ALL
+};
+
+#define POLICY_OVERRIDE_VERSION    "/data/security/current/selinux_version"
+#define POLICY_BASE_VERSION        "/selinux_version"
+static int policy_index = 0;
+
+static void set_policy_index(void)
+{
+	int fd_base = -1, fd_override = -1;
+	struct stat sb_base;
+	struct stat sb_override;
+	void *map_base, *map_override;
+
+	policy_index = 0;
+
+	fd_base = open(POLICY_BASE_VERSION, O_RDONLY | O_NOFOLLOW);
+	if (fd_base < 0)
+		return;
+
+	if (fstat(fd_base, &sb_base) < 0) {
+		close(fd_base);
+		return;
+	}
+
+	fd_override = open(POLICY_OVERRIDE_VERSION, O_RDONLY | O_NOFOLLOW);
+	if (fd_override < 0) {
+		close(fd_base);
+		return;
+	}
+
+	if (fstat(fd_override, &sb_override) < 0) {
+		close(fd_base);
+		close(fd_override);
+		return;
+	}
+
+	if (sb_base.st_size != sb_override.st_size) {
+		close(fd_base);
+		close(fd_override);
+		return;
+	}
+
+	map_base = mmap(NULL, sb_base.st_size, PROT_READ, MAP_PRIVATE, fd_base, 0);
+	if (map_base == MAP_FAILED) {
+		close(fd_base);
+		close(fd_override);
+		return;
+	}
+
+	map_override = mmap(NULL, sb_override.st_size, PROT_READ, MAP_PRIVATE, fd_override, 0);
+	if (map_override == MAP_FAILED) {
+		munmap(map_base, sb_base.st_size);
+		close(fd_base);
+		close(fd_override);
+		return;
+	}
+
+	if (memcmp(map_base, map_override, sb_base.st_size) == 0)
+		policy_index = 1;
+
+
+	close(fd_base);
+	close(fd_override);
+	munmap(map_base, sb_base.st_size);
+	munmap(map_override, sb_override.st_size);
+}
+
+bool selinux_android_use_data_policy(void)
+{
+	set_policy_index();
+	return (policy_index == 1);
+}
+
+#if DEBUG
+static char const * const levelFromName[] = {
+	"none",
+	"app",
+	"user",
+	"all"
+};
+#endif
+
+struct prefix_str {
+	size_t len;
+	char *str;
+	char is_prefix;
+};
+
+static void free_prefix_str(struct prefix_str *p)
+{
+	if (!p)
+		return;
+	free(p->str);
+}
+
+struct seapp_context {
+	/* input selectors */
+	char isSystemServer;
+	struct prefix_str user;
+	char *seinfo;
+	struct prefix_str name;
+	struct prefix_str path;
+	/* outputs */
+	char *domain;
+	char *type;
+	char *level;
+	char *sebool;
+	enum levelFrom levelFrom;
+};
+
+static void free_seapp_context(struct seapp_context *s)
+{
+	if (!s)
+		return;
+
+	free_prefix_str(&s->user);
+	free(s->seinfo);
+	free_prefix_str(&s->name);
+	free_prefix_str(&s->path);
+	free(s->domain);
+	free(s->type);
+	free(s->level);
+	free(s->sebool);
+}
+
+static int seapp_context_cmp(const void *A, const void *B)
+{
+	const struct seapp_context *const *sp1 = (const struct seapp_context *const *) A;
+	const struct seapp_context *const *sp2 = (const struct seapp_context *const *) B;
+	const struct seapp_context *s1 = *sp1, *s2 = *sp2;
+
+	/* Give precedence to isSystemServer=true. */
+	if (s1->isSystemServer != s2->isSystemServer)
+		return (s1->isSystemServer ? -1 : 1);
+
+	/* Give precedence to a specified user= over an unspecified user=. */
+	if (s1->user.str && !s2->user.str)
+		return -1;
+	if (!s1->user.str && s2->user.str)
+		return 1;
+
+	if (s1->user.str) {
+		/* Give precedence to a fixed user= string over a prefix. */
+		if (s1->user.is_prefix != s2->user.is_prefix)
+			return (s2->user.is_prefix ? -1 : 1);
+
+		/* Give precedence to a longer prefix over a shorter prefix. */
+		if (s1->user.is_prefix && s1->user.len != s2->user.len)
+			return (s1->user.len > s2->user.len) ? -1 : 1;
+	}
+
+	/* Give precedence to a specified seinfo= over an unspecified seinfo=. */
+	if (s1->seinfo && !s2->seinfo)
+		return -1;
+	if (!s1->seinfo && s2->seinfo)
+		return 1;
+
+	/* Give precedence to a specified name= over an unspecified name=. */
+	if (s1->name.str && !s2->name.str)
+		return -1;
+	if (!s1->name.str && s2->name.str)
+		return 1;
+
+	if (s1->name.str) {
+		/* Give precedence to a fixed name= string over a prefix. */
+		if (s1->name.is_prefix != s2->name.is_prefix)
+			return (s2->name.is_prefix ? -1 : 1);
+
+		/* Give precedence to a longer prefix over a shorter prefix. */
+		if (s1->name.is_prefix && s1->name.len != s2->name.len)
+			return (s1->name.len > s2->name.len) ? -1 : 1;
+	}
+
+	/* Give precedence to a specified path= over an unspecified path=. */
+	if (s1->path.str && !s2->path.str)
+		return -1;
+	if (!s1->path.str && s2->path.str)
+		return 1;
+
+	if (s1->path.str) {
+		/* Give precedence to a fixed path= string over a prefix. */
+		if (s1->path.is_prefix != s2->path.is_prefix)
+			return (s2->path.is_prefix ? -1 : 1);
+
+		/* Give precedence to a longer prefix over a shorter prefix. */
+		if (s1->path.is_prefix && s1->path.len != s2->path.len)
+			return (s1->path.len > s2->path.len) ? -1 : 1;
+	}
+
+        /* Give precedence to a specified sebool= over an unspecified sebool=. */
+        if (s1->sebool && !s2->sebool)
+                return -1;
+        if (!s1->sebool && s2->sebool)
+                return 1;
+
+	/* Anything else has equal precedence. */
+	return 0;
+}
+
+static struct seapp_context **seapp_contexts = NULL;
+static int nspec = 0;
+
+static void free_seapp_contexts(void)
+{
+	int n;
+
+	if (!seapp_contexts)
+		return;
+
+	for (n = 0; n < nspec; n++)
+		free_seapp_context(seapp_contexts[n]);
+
+	free(seapp_contexts);
+	seapp_contexts = NULL;
+	nspec = 0;
+}
+
+int selinux_android_seapp_context_reload(void)
+{
+	FILE *fp = NULL;
+	char line_buf[BUFSIZ];
+	char *token;
+	unsigned lineno;
+	struct seapp_context *cur;
+	char *p, *name = NULL, *value = NULL, *saveptr;
+	size_t len;
+	int n, ret;
+
+	set_policy_index();
+
+	fp = fopen(seapp_contexts_file[policy_index], "r");
+	if (!fp) {
+		selinux_log(SELINUX_ERROR, "%s:  could not open any seapp_contexts file", __FUNCTION__);
+		return -1;
+	}
+
+	free_seapp_contexts();
+
+	nspec = 0;
+	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
+		p = line_buf;
+		while (isspace(*p))
+			p++;
+		if (*p == '#' || *p == 0)
+			continue;
+		nspec++;
+	}
+
+	seapp_contexts = (struct seapp_context **) calloc(nspec, sizeof(struct seapp_context *));
+	if (!seapp_contexts)
+		goto oom;
+
+	rewind(fp);
+	nspec = 0;
+	lineno = 1;
+	while (fgets(line_buf, sizeof line_buf - 1, fp)) {
+		len = strlen(line_buf);
+		if (line_buf[len - 1] == '\n')
+			line_buf[len - 1] = 0;
+		p = line_buf;
+		while (isspace(*p))
+			p++;
+		if (*p == '#' || *p == 0)
+			continue;
+
+		cur = (struct seapp_context *) calloc(1, sizeof(struct seapp_context));
+		if (!cur)
+			goto oom;
+
+		token = strtok_r(p, " \t", &saveptr);
+		if (!token) {
+			free_seapp_context(cur);
+			goto err;
+		}
+
+		while (1) {
+			name = token;
+			value = strchr(name, '=');
+			if (!value) {
+				free_seapp_context(cur);
+				goto err;
+			}
+			*value++ = 0;
+
+			if (!strcasecmp(name, "isSystemServer")) {
+				if (!strcasecmp(value, "true"))
+					cur->isSystemServer = 1;
+				else if (!strcasecmp(value, "false"))
+					cur->isSystemServer = 0;
+				else {
+					free_seapp_context(cur);
+					goto err;
+				}
+			} else if (!strcasecmp(name, "user")) {
+				cur->user.str = strdup(value);
+				if (!cur->user.str) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+				cur->user.len = strlen(cur->user.str);
+				if (cur->user.str[cur->user.len-1] == '*')
+					cur->user.is_prefix = 1;
+			} else if (!strcasecmp(name, "seinfo")) {
+				cur->seinfo = strdup(value);
+				if (!cur->seinfo) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+			} else if (!strcasecmp(name, "name")) {
+				cur->name.str = strdup(value);
+				if (!cur->name.str) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+				cur->name.len = strlen(cur->name.str);
+				if (cur->name.str[cur->name.len-1] == '*')
+					cur->name.is_prefix = 1;
+			} else if (!strcasecmp(name, "domain")) {
+				cur->domain = strdup(value);
+				if (!cur->domain) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+			} else if (!strcasecmp(name, "type")) {
+				cur->type = strdup(value);
+				if (!cur->type) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+			} else if (!strcasecmp(name, "levelFromUid")) {
+				if (!strcasecmp(value, "true"))
+					cur->levelFrom = LEVELFROM_APP;
+				else if (!strcasecmp(value, "false"))
+					cur->levelFrom = LEVELFROM_NONE;
+				else {
+					free_seapp_context(cur);
+					goto err;
+				}
+			} else if (!strcasecmp(name, "levelFrom")) {
+				if (!strcasecmp(value, "none"))
+					cur->levelFrom = LEVELFROM_NONE;
+				else if (!strcasecmp(value, "app"))
+					cur->levelFrom = LEVELFROM_APP;
+				else if (!strcasecmp(value, "user"))
+					cur->levelFrom = LEVELFROM_USER;
+				else if (!strcasecmp(value, "all"))
+					cur->levelFrom = LEVELFROM_ALL;
+				else {
+					free_seapp_context(cur);
+					goto err;
+				}
+			} else if (!strcasecmp(name, "level")) {
+				cur->level = strdup(value);
+				if (!cur->level) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+			} else if (!strcasecmp(name, "path")) {
+				cur->path.str = strdup(value);
+				if (!cur->path.str) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+				cur->path.len = strlen(cur->path.str);
+				if (cur->path.str[cur->path.len-1] == '*')
+					cur->path.is_prefix = 1;
+			} else if (!strcasecmp(name, "sebool")) {
+				cur->sebool = strdup(value);
+				if (!cur->sebool) {
+					free_seapp_context(cur);
+					goto oom;
+				}
+			} else {
+				free_seapp_context(cur);
+				goto err;
+			}
+
+			token = strtok_r(NULL, " \t", &saveptr);
+			if (!token)
+				break;
+		}
+
+		if (cur->name.str &&
+		    (!cur->seinfo || !strcmp(cur->seinfo, "default"))) {
+			selinux_log(SELINUX_ERROR, "%s:  No specific seinfo value specified with name=\"%s\", on line %u:  insecure configuration!\n",
+				    seapp_contexts_file[policy_index], cur->name.str, lineno);
+			free_seapp_context(cur);
+			goto err;
+		}
+
+		seapp_contexts[nspec] = cur;
+		nspec++;
+		lineno++;
+	}
+
+	qsort(seapp_contexts, nspec, sizeof(struct seapp_context *),
+	      seapp_context_cmp);
+
+#if DEBUG
+	{
+		int i;
+		for (i = 0; i < nspec; i++) {
+			cur = seapp_contexts[i];
+			selinux_log(SELINUX_INFO, "%s:  isSystemServer=%s user=%s seinfo=%s name=%s path=%s sebool=%s -> domain=%s type=%s level=%s levelFrom=%s",
+			__FUNCTION__,
+			cur->isSystemServer ? "true" : "false", cur->user.str,
+			cur->seinfo, cur->name.str, cur->path.str, cur->sebool, cur->domain,
+			cur->type, cur->level,
+			levelFromName[cur->levelFrom]);
+		}
+	}
+#endif
+
+	ret = 0;
+
+out:
+	fclose(fp);
+	return ret;
+
+err:
+	selinux_log(SELINUX_ERROR, "%s:  Invalid entry on line %u\n",
+		    seapp_contexts_file[policy_index], lineno);
+	free_seapp_contexts();
+	ret = -1;
+	goto out;
+oom:
+	selinux_log(SELINUX_ERROR, 
+		    "%s:  Out of memory\n", __FUNCTION__);
+	free_seapp_contexts();
+	ret = -1;
+	goto out;
+}
+
+
+static void seapp_context_init(void)
+{
+        selinux_android_seapp_context_reload();
+}
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+/*
+ * Max id that can be mapped to category set uniquely
+ * using the current scheme.
+ */
+#define CAT_MAPPING_MAX_ID (0x1<<16)
+
+enum seapp_kind {
+	SEAPP_TYPE,
+	SEAPP_DOMAIN
+};
+
+static int seapp_context_lookup(enum seapp_kind kind,
+				uid_t uid,
+				int isSystemServer,
+				const char *seinfo,
+				const char *pkgname,
+				const char *path,
+				context_t ctx)
+{
+	const char *username = NULL;
+	struct seapp_context *cur = NULL;
+	int i;
+	size_t n;
+	uid_t userid;
+	uid_t appid;
+
+	__selinux_once(once, seapp_context_init);
+
+	userid = uid / AID_USER;
+	appid = uid % AID_USER;
+	if (appid < AID_APP) {
+		for (n = 0; n < android_id_count; n++) {
+			if (android_ids[n].aid == appid) {
+				username = android_ids[n].name;
+				break;
+			}
+		}
+		if (!username)
+			goto err;
+	} else if (appid < AID_ISOLATED_START) {
+		username = "_app";
+		appid -= AID_APP;
+	} else {
+		username = "_isolated";
+		appid -= AID_ISOLATED_START;
+	}
+
+	if (appid >= CAT_MAPPING_MAX_ID || userid >= CAT_MAPPING_MAX_ID)
+		goto err;
+
+	for (i = 0; i < nspec; i++) {
+		cur = seapp_contexts[i];
+
+		if (cur->isSystemServer != isSystemServer)
+			continue;
+
+		if (cur->user.str) {
+			if (cur->user.is_prefix) {
+				if (strncasecmp(username, cur->user.str, cur->user.len-1))
+					continue;
+			} else {
+				if (strcasecmp(username, cur->user.str))
+					continue;
+			}
+		}
+
+		if (cur->seinfo) {
+			if (!seinfo || strcasecmp(seinfo, cur->seinfo))
+				continue;
+		}
+
+		if (cur->name.str) {
+			if(!pkgname)
+				continue;
+
+			if (cur->name.is_prefix) {
+				if (strncasecmp(pkgname, cur->name.str, cur->name.len-1))
+					continue;
+			} else {
+				if (strcasecmp(pkgname, cur->name.str))
+					continue;
+			}
+		}
+
+		if (cur->path.str) {
+			if (!path)
+				continue;
+
+			if (cur->path.is_prefix) {
+				if (strncmp(path, cur->path.str, cur->path.len-1))
+					continue;
+			} else {
+				if (strcmp(path, cur->path.str))
+					continue;
+			}
+		}
+
+		if (kind == SEAPP_TYPE && !cur->type)
+			continue;
+		else if (kind == SEAPP_DOMAIN && !cur->domain)
+			continue;
+
+		if (cur->sebool) {
+			int value = security_get_boolean_active(cur->sebool);
+			if (value == 0)
+				continue;
+			else if (value == -1) {
+				selinux_log(SELINUX_ERROR, \
+				"Could not find boolean: %s ", cur->sebool);
+				goto err;
+			}
+		}
+
+		if (kind == SEAPP_TYPE) {
+			if (context_type_set(ctx, cur->type))
+				goto oom;
+		} else if (kind == SEAPP_DOMAIN) {
+			if (context_type_set(ctx, cur->domain))
+				goto oom;
+		}
+
+		if (cur->levelFrom != LEVELFROM_NONE) {
+			char level[255];
+			switch (cur->levelFrom) {
+			case LEVELFROM_APP:
+				snprintf(level, sizeof level, "s0:c%u,c%u",
+					 appid & 0xff,
+					 256 + (appid>>8 & 0xff));
+				break;
+			case LEVELFROM_USER:
+				snprintf(level, sizeof level, "s0:c%u,c%u",
+					 512 + (userid & 0xff),
+					 768 + (userid>>8 & 0xff));
+				break;
+			case LEVELFROM_ALL:
+				snprintf(level, sizeof level, "s0:c%u,c%u,c%u,c%u",
+					 appid & 0xff,
+					 256 + (appid>>8 & 0xff),
+					 512 + (userid & 0xff),
+					 768 + (userid>>8 & 0xff));
+				break;
+			default:
+				goto err;
+			}
+			if (context_range_set(ctx, level))
+				goto oom;
+		} else if (cur->level) {
+			if (context_range_set(ctx, cur->level))
+				goto oom;
+		}
+
+		break;
+	}
+
+	if (kind == SEAPP_DOMAIN && i == nspec) {
+		/*
+		 * No match.
+		 * Fail to prevent staying in the zygote's context.
+		 */
+		selinux_log(SELINUX_ERROR,
+			    "%s:  No match for app with uid %d, seinfo %s, name %s\n",
+			    __FUNCTION__, uid, seinfo, pkgname);
+
+		if (security_getenforce() == 1)
+			goto err;
+	}
+
+	return 0;
+err:
+	return -1;
+oom:
+	return -2;
+}
+
+int selinux_android_setfilecon(const char *pkgdir,
+				const char *pkgname,
+				const char *seinfo,
+				uid_t uid)
+{
+	char *orig_ctx_str = NULL;
+	char *ctx_str = NULL;
+	context_t ctx = NULL;
+	int rc = -1;
+
+	if (is_selinux_enabled() <= 0)
+		return 0;
+
+	rc = getfilecon(pkgdir, &ctx_str);
+	if (rc < 0)
+		goto err;
+
+	ctx = context_new(ctx_str);
+	orig_ctx_str = ctx_str;
+	if (!ctx)
+		goto oom;
+
+	rc = seapp_context_lookup(SEAPP_TYPE, uid, 0, seinfo, pkgname, NULL, ctx);
+	if (rc == -1)
+		goto err;
+	else if (rc == -2)
+		goto oom;
+
+	ctx_str = context_str(ctx);
+	if (!ctx_str)
+		goto oom;
+
+	rc = security_check_context(ctx_str);
+	if (rc < 0)
+		goto err;
+
+	if (strcmp(ctx_str, orig_ctx_str)) {
+		rc = setfilecon(pkgdir, ctx_str);
+		if (rc < 0)
+			goto err;
+	}
+
+	rc = 0;
+out:
+	freecon(orig_ctx_str);
+	context_free(ctx);
+	return rc;
+err:
+	selinux_log(SELINUX_ERROR, "%s:  Error setting context for pkgdir %s, uid %d: %s\n",
+		    __FUNCTION__, pkgdir, uid, strerror(errno));
+	rc = -1;
+	goto out;
+oom:
+	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
+	rc = -1;
+	goto out;
+}
+
+int selinux_android_setcontext(uid_t uid,
+			       int isSystemServer,
+			       const char *seinfo,
+			       const char *pkgname)
+{
+	char *orig_ctx_str = NULL, *ctx_str;
+	context_t ctx = NULL;
+	int rc = -1;
+
+	if (is_selinux_enabled() <= 0)
+		return 0;
+
+	rc = getcon(&ctx_str);
+	if (rc)
+		goto err;
+
+	ctx = context_new(ctx_str);
+	orig_ctx_str = ctx_str;
+	if (!ctx)
+		goto oom;
+
+	rc = seapp_context_lookup(SEAPP_DOMAIN, uid, isSystemServer, seinfo, pkgname, NULL, ctx);
+	if (rc == -1)
+		goto err;
+	else if (rc == -2)
+		goto oom;
+
+	ctx_str = context_str(ctx);
+	if (!ctx_str)
+		goto oom;
+
+	rc = security_check_context(ctx_str);
+	if (rc < 0)
+		goto err;
+
+	if (strcmp(ctx_str, orig_ctx_str)) {
+		rc = setcon(ctx_str);
+		if (rc < 0)
+			goto err;
+	}
+
+	rc = 0;
+out:
+	freecon(orig_ctx_str);
+	context_free(ctx);
+	avc_netlink_close();
+	return rc;
+err:
+	if (isSystemServer)
+		selinux_log(SELINUX_ERROR,
+				"%s:  Error setting context for system server: %s\n",
+				__FUNCTION__, strerror(errno));
+	else 
+		selinux_log(SELINUX_ERROR,
+				"%s:  Error setting context for app with uid %d, seinfo %s: %s\n",
+				__FUNCTION__, uid, seinfo, strerror(errno));
+
+	rc = -1;
+	goto out;
+oom:
+	selinux_log(SELINUX_ERROR, "%s:  Out of memory\n", __FUNCTION__);
+	rc = -1;
+	goto out;
+}
+
+static struct selabel_handle *sehandle = NULL;
+#define FC_DIGEST_SIZE SHA_DIGEST_SIZE
+static uint8_t fc_digest[FC_DIGEST_SIZE];
+
+static struct selabel_handle *get_selabel_handle(const struct selinux_opt opts[])
+{
+    struct selabel_handle *h;
+    int fd;
+    struct stat sb;
+    void *map;
+
+    set_policy_index();
+
+    h = selabel_open(SELABEL_CTX_FILE, &opts[policy_index], 1);
+    if (!h)
+        return NULL;
+
+    fd = open(opts[policy_index].value, O_RDONLY | O_NOFOLLOW);
+    if (fd < 0) {
+        selinux_log(SELINUX_ERROR, "SELinux:  Could not open %s:  %s\n",
+                    opts[policy_index].value, strerror(errno));
+        goto err;
+    }
+    if (fstat(fd, &sb) < 0) {
+        selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
+                    opts[policy_index].value, strerror(errno));
+        close(fd);
+        goto err;
+    }
+    map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+    if (map == MAP_FAILED) {
+        selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
+                    opts[policy_index].value, strerror(errno));
+        close(fd);
+        goto err;
+    }
+    SHA_hash(map, sb.st_size, fc_digest);
+    munmap(map, sb.st_size);
+    close(fd);
+
+    selinux_log(SELINUX_INFO, "SELinux: Loaded file_contexts from %s\n",
+                opts[policy_index].value);
+
+    return h;
+
+err:
+    selabel_close(h);
+    return NULL;
+}
+
+static struct selabel_handle *file_context_open(void)
+{
+	struct selabel_handle *h;
+
+	h = get_selabel_handle(seopts);
+
+	if (!h)
+		selinux_log(SELINUX_ERROR, "%s: Error getting file context handle (%s)\n",
+				__FUNCTION__, strerror(errno));
+	return h;
+}
+
+static void file_context_init(void)
+{
+    if (!sehandle)
+        sehandle = file_context_open();
+}
+
+static pthread_once_t fc_once = PTHREAD_ONCE_INIT;
+
+struct pkgInfo {
+    char *name;
+    uid_t uid;
+    bool debuggable;
+    char *dataDir;
+    char *seinfo;
+    struct pkgInfo *next;
+};
+
+#define PKGTAB_SIZE 256
+static struct pkgInfo *pkgTab[PKGTAB_SIZE];
+
+static unsigned int pkghash(const char *pkgname)
+{
+    unsigned int h = 7;
+    for (; *pkgname; pkgname++) {
+        h = h * 31 + *pkgname;
+    }
+    return h & (PKGTAB_SIZE - 1);
+}
+
+/* The file containing the list of installed packages on the system */
+#define PACKAGES_LIST_FILE  "/data/system/packages.list"
+
+static void package_info_init(void)
+{
+    char *buf = NULL;
+    size_t buflen = 0;
+    ssize_t bytesread;
+    FILE *fp;
+    char *cur, *next;
+    struct pkgInfo *pkgInfo = NULL;
+    unsigned int hash;
+    unsigned long lineno = 1;
+
+    fp = fopen(PACKAGES_LIST_FILE, "r");
+    if (!fp) {
+        selinux_log(SELINUX_ERROR, "SELinux:  Could not open %s:  %s.\n",
+                    PACKAGES_LIST_FILE, strerror(errno));
+        return;
+    }
+    while ((bytesread = getline(&buf, &buflen, fp)) > 0) {
+        pkgInfo = calloc(1, sizeof(*pkgInfo));
+        if (!pkgInfo)
+            goto err;
+        next = buf;
+        cur = strsep(&next, " \t\n");
+        if (!cur)
+            goto err;
+        pkgInfo->name = strdup(cur);
+        if (!pkgInfo->name)
+            goto err;
+        cur = strsep(&next, " \t\n");
+        if (!cur)
+            goto err;
+        pkgInfo->uid = atoi(cur);
+        if (!pkgInfo->uid)
+            goto err;
+        cur = strsep(&next, " \t\n");
+        if (!cur)
+            goto err;
+        pkgInfo->debuggable = atoi(cur);
+        cur = strsep(&next, " \t\n");
+        if (!cur)
+            goto err;
+        pkgInfo->dataDir = strdup(cur);
+        if (!pkgInfo->dataDir)
+            goto err;
+        cur = strsep(&next, " \t\n");
+        if (!cur)
+            goto err;
+        pkgInfo->seinfo = strdup(cur);
+        if (!pkgInfo->seinfo)
+            goto err;
+
+        hash = pkghash(pkgInfo->name);
+        if (pkgTab[hash])
+            pkgInfo->next = pkgTab[hash];
+        pkgTab[hash] = pkgInfo;
+
+        lineno++;
+    }
+
+#if DEBUG
+    {
+        unsigned int buckets, entries, chainlen, longestchain;
+
+        buckets = entries = longestchain = 0;
+        for (hash = 0; hash < PKGTAB_SIZE; hash++) {
+            if (pkgTab[hash]) {
+                buckets++;
+                chainlen = 0;
+                for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
+                    chainlen++;
+                    selinux_log(SELINUX_INFO, "%s:  name=%s uid=%u debuggable=%s dataDir=%s seinfo=%s\n",
+                                __FUNCTION__,
+                                pkgInfo->name, pkgInfo->uid, pkgInfo->debuggable ? "true" : "false", pkgInfo->dataDir, pkgInfo->seinfo);
+                }
+                entries += chainlen;
+                if (longestchain < chainlen)
+                    longestchain = chainlen;
+            }
+        }
+        selinux_log(SELINUX_INFO, "SELinux:  %d pkg entries and %d/%d buckets used, longest chain %d\n", entries, buckets, PKGTAB_SIZE, longestchain);
+    }
+#endif
+
+out:
+    free(buf);
+    fclose(fp);
+    return;
+
+err:
+    selinux_log(SELINUX_ERROR, "SELinux:  Error reading %s on line %lu.\n",
+                PACKAGES_LIST_FILE, lineno);
+    if (pkgInfo) {
+        free(pkgInfo->name);
+        free(pkgInfo->dataDir);
+        free(pkgInfo->seinfo);
+        free(pkgInfo);
+    }
+    goto out;
+}
+
+static pthread_once_t pkg_once = PTHREAD_ONCE_INIT;
+
+struct pkgInfo *package_info_lookup(const char *name)
+{
+    struct pkgInfo *pkgInfo;
+    unsigned int hash;
+
+    __selinux_once(pkg_once, package_info_init);
+
+    hash = pkghash(name);
+    for (pkgInfo = pkgTab[hash]; pkgInfo; pkgInfo = pkgInfo->next) {
+        if (!strcmp(name, pkgInfo->name))
+            return pkgInfo;
+    }
+    return NULL;
+}
+
+/* The path prefixes of package data directories. */
+#define DATA_DATA_PATH "/data/data"
+#define DATA_USER_PATH "/data/user"
+#define DATA_DATA_PREFIX DATA_DATA_PATH "/"
+#define DATA_USER_PREFIX DATA_USER_PATH "/"
+
+static int pkgdir_selabel_lookup(const char *pathname,
+                                 const char *seinfo,
+                                 uid_t uid,
+                                 char **secontextp)
+{
+    char *pkgname = NULL, *end = NULL;
+    struct pkgInfo *pkgInfo = NULL;
+    char *secontext = *secontextp;
+    context_t ctx = NULL;
+    int rc = 0;
+
+    /* Skip directory prefix before package name. */
+    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1)) {
+        pathname += sizeof(DATA_DATA_PREFIX) - 1;
+    } else if (!strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
+        pathname += sizeof(DATA_USER_PREFIX) - 1;
+        while (isdigit(*pathname))
+            pathname++;
+        if (*pathname == '/')
+            pathname++;
+        else
+            return 0;
+    } else
+        return 0;
+
+    if (!(*pathname))
+        return 0;
+
+    pkgname = strdup(pathname);
+    if (!pkgname)
+        return -1;
+
+    for (end = pkgname; *end && *end != '/'; end++)
+        ;
+    pathname = end;
+    if (*end)
+        pathname++;
+    *end = '\0';
+
+    if (!seinfo) {
+        pkgInfo = package_info_lookup(pkgname);
+        if (!pkgInfo) {
+            selinux_log(SELINUX_WARNING, "SELinux:  Could not look up information for package %s, cannot restorecon %s.\n",
+                        pkgname, pathname);
+            free(pkgname);
+            return -1;
+        }
+    }
+
+    ctx = context_new(secontext);
+    if (!ctx)
+        goto err;
+
+    rc = seapp_context_lookup(SEAPP_TYPE, pkgInfo ? pkgInfo->uid : uid, 0,
+                              pkgInfo ? pkgInfo->seinfo : seinfo, pkgInfo ? pkgInfo->name : pkgname, pathname, ctx);
+    if (rc < 0)
+        goto err;
+
+    secontext = context_str(ctx);
+    if (!secontext)
+        goto err;
+
+    if (!strcmp(secontext, *secontextp))
+        goto out;
+
+    rc = security_check_context(secontext);
+    if (rc < 0)
+        goto err;
+
+    freecon(*secontextp);
+    *secontextp = strdup(secontext);
+    if (!(*secontextp))
+        goto err;
+
+    rc = 0;
+
+out:
+    free(pkgname);
+    context_free(ctx);
+    return rc;
+err:
+    selinux_log(SELINUX_ERROR, "%s:  Error looking up context for path %s, pkgname %s, seinfo %s, uid %u: %s\n",
+                __FUNCTION__, pathname, pkgname, pkgInfo->seinfo, pkgInfo->uid, strerror(errno));
+    rc = -1;
+    goto out;
+}
+
+#define RESTORECON_LAST "security.restorecon_last"
+
+static int restorecon_sb(const char *pathname, const struct stat *sb,
+                         bool nochange, bool verbose,
+                         const char *seinfo, uid_t uid)
+{
+    char *secontext = NULL;
+    char *oldsecontext = NULL;
+    int rc = 0;
+
+    if (selabel_lookup(sehandle, &secontext, pathname, sb->st_mode) < 0)
+        return 0;  /* no match, but not an error */
+
+    if (lgetfilecon(pathname, &oldsecontext) < 0)
+        goto err;
+
+    /*
+     * For subdirectories of /data/data or /data/user, we ignore selabel_lookup()
+     * and use pkgdir_selabel_lookup() instead. Files within those directories
+     * have different labeling rules, based off of /seapp_contexts, and
+     * installd is responsible for managing these labels instead of init.
+     */
+    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
+        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1)) {
+        if (pkgdir_selabel_lookup(pathname, seinfo, uid, &secontext) < 0)
+            goto err;
+    }
+
+    if (strcmp(oldsecontext, secontext) != 0) {
+        if (verbose)
+            selinux_log(SELINUX_INFO,
+                        "SELinux:  Relabeling %s from %s to %s.\n", pathname, oldsecontext, secontext);
+        if (!nochange) {
+            if (lsetfilecon(pathname, secontext) < 0)
+                goto err;
+        }
+    }
+
+    rc = 0;
+
+out:
+    freecon(oldsecontext);
+    freecon(secontext);
+    return rc;
+
+err:
+    selinux_log(SELINUX_ERROR,
+                "SELinux: Could not set context for %s:  %s\n",
+                pathname, strerror(errno));
+    rc = -1;
+    goto out;
+}
+
+static int selinux_android_restorecon_common(const char* pathname,
+                                             const char *seinfo,
+                                             uid_t uid,
+                                             unsigned int flags)
+{
+    bool nochange = (flags & SELINUX_ANDROID_RESTORECON_NOCHANGE) ? true : false;
+    bool verbose = (flags & SELINUX_ANDROID_RESTORECON_VERBOSE) ? true : false;
+    bool recurse = (flags & SELINUX_ANDROID_RESTORECON_RECURSE) ? true : false;
+    bool force = (flags & SELINUX_ANDROID_RESTORECON_FORCE) ? true : false;
+    bool datadata = (flags & SELINUX_ANDROID_RESTORECON_DATADATA) ? true : false;
+    bool issys = strcmp(pathname, "/sys") == 0 ? true : false;
+    bool setrestoreconlast = true;
+    struct stat sb;
+    FTS *fts;
+    FTSENT *ftsent;
+    char *const paths[2] = { __UNCONST(pathname), NULL };
+    int ftsflags = FTS_COMFOLLOW | FTS_NOCHDIR | FTS_XDEV | FTS_PHYSICAL;
+    int error, sverrno;
+    char xattr_value[FC_DIGEST_SIZE];
+    ssize_t size;
+
+    if (is_selinux_enabled() <= 0)
+        return 0;
+
+    __selinux_once(fc_once, file_context_init);
+
+    if (!sehandle)
+        return 0;
+
+    if (!recurse) {
+        if (lstat(pathname, &sb) < 0)
+            return -1;
+
+        return restorecon_sb(pathname, &sb, nochange, verbose, seinfo, uid);
+    }
+
+    /*
+     * Ignore restorecon_last on /data/data or /data/user
+     * since their labeling is based on seapp_contexts and seinfo
+     * assignments rather than file_contexts and is managed by
+     * installd rather than init.
+     */
+    if (!strncmp(pathname, DATA_DATA_PREFIX, sizeof(DATA_DATA_PREFIX)-1) ||
+        !strncmp(pathname, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))
+        setrestoreconlast = false;
+
+    if (setrestoreconlast) {
+        size = getxattr(pathname, RESTORECON_LAST, xattr_value, sizeof fc_digest);
+        if (!force && size == sizeof fc_digest && memcmp(fc_digest, xattr_value, sizeof fc_digest) == 0) {
+            selinux_log(SELINUX_INFO,
+                        "SELinux: Skipping restorecon_recursive(%s)\n",
+                        pathname);
+            return 0;
+        }
+    }
+
+    fts = fts_open(paths, ftsflags, NULL);
+    if (!fts)
+        return -1;
+
+    error = 0;
+    while ((ftsent = fts_read(fts)) != NULL) {
+        switch (ftsent->fts_info) {
+        case FTS_DC:
+            selinux_log(SELINUX_ERROR,
+                        "SELinux:  Directory cycle on %s.\n", ftsent->fts_path);
+            errno = ELOOP;
+            error = -1;
+            goto out;
+        case FTS_DP:
+            continue;
+        case FTS_DNR:
+            selinux_log(SELINUX_ERROR,
+                        "SELinux:  Could not read %s: %s.\n", ftsent->fts_path, strerror(errno));
+            fts_set(fts, ftsent, FTS_SKIP);
+            continue;
+        case FTS_NS:
+            selinux_log(SELINUX_ERROR,
+                        "SELinux:  Could not stat %s: %s.\n", ftsent->fts_path, strerror(errno));
+            fts_set(fts, ftsent, FTS_SKIP);
+            continue;
+        case FTS_ERR:
+            selinux_log(SELINUX_ERROR,
+                        "SELinux:  Error on %s: %s.\n", ftsent->fts_path, strerror(errno));
+            fts_set(fts, ftsent, FTS_SKIP);
+            continue;
+        case FTS_D:
+            if (issys && !selabel_partial_match(sehandle, ftsent->fts_path)) {
+                fts_set(fts, ftsent, FTS_SKIP);
+                continue;
+            }
+            if (!datadata &&
+                (!strcmp(ftsent->fts_path, DATA_DATA_PATH) ||
+                 !strncmp(ftsent->fts_path, DATA_USER_PREFIX, sizeof(DATA_USER_PREFIX)-1))) {
+                // Don't label anything below this directory.
+                fts_set(fts, ftsent, FTS_SKIP);
+                // but fall through and make sure we label the directory itself
+            }
+            /* fall through */
+        default:
+            error |= restorecon_sb(ftsent->fts_path, ftsent->fts_statp, nochange, verbose, seinfo, uid);
+            break;
+        }
+    }
+
+    // Labeling successful. Mark the top level directory as completed.
+    if (setrestoreconlast && !nochange && !error)
+        setxattr(pathname, RESTORECON_LAST, fc_digest, sizeof fc_digest, 0);
+
+out:
+    sverrno = errno;
+    (void) fts_close(fts);
+    errno = sverrno;
+    return error;
+}
+
+int selinux_android_restorecon(const char *file, unsigned int flags)
+{
+    return selinux_android_restorecon_common(file, NULL, -1, flags);
+}
+
+int selinux_android_restorecon_pkgdir(const char *pkgdir,
+                                      const char *seinfo,
+                                      uid_t uid,
+                                      unsigned int flags)
+{
+    return selinux_android_restorecon_common(pkgdir, seinfo, uid, flags | SELINUX_ANDROID_RESTORECON_DATADATA);
+}
+
+struct selabel_handle* selinux_android_file_context_handle(void)
+{
+    return file_context_open();
+}
+
+void selinux_android_set_sehandle(const struct selabel_handle *hndl)
+{
+    sehandle = (struct selabel_handle *) hndl;
+}
+
+static int selinux_android_load_policy_helper(bool reload)
+{
+	int fd = -1, rc;
+	struct stat sb;
+	void *map = NULL;
+
+	/*
+	 * If reloading policy and there is no /data policy or
+	 * that /data policy has the wrong version or the /data
+	 * policy is disabled via safe mode, then just return.
+	 * There is no point in reloading policy from / a second time.
+	 */
+	if (reload && !selinux_android_use_data_policy())
+		return 0;
+
+	fd = open(sepolicy_file[policy_index], O_RDONLY | O_NOFOLLOW);
+	if (fd < 0) {
+		selinux_log(SELINUX_ERROR, "SELinux:  Could not open sepolicy:  %s\n",
+				strerror(errno));
+		return -1;
+	}
+	if (fstat(fd, &sb) < 0) {
+		selinux_log(SELINUX_ERROR, "SELinux:  Could not stat %s:  %s\n",
+				sepolicy_file[policy_index], strerror(errno));
+		close(fd);
+		return -1;
+	}
+	map = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+	if (map == MAP_FAILED) {
+		selinux_log(SELINUX_ERROR, "SELinux:  Could not map %s:  %s\n",
+			sepolicy_file[policy_index], strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	rc = security_load_policy(map, sb.st_size);
+	if (rc < 0) {
+		selinux_log(SELINUX_ERROR, "SELinux:  Could not load policy:  %s\n",
+			strerror(errno));
+		munmap(map, sb.st_size);
+		close(fd);
+		return -1;
+	}
+
+	munmap(map, sb.st_size);
+	close(fd);
+	selinux_log(SELINUX_INFO, "SELinux: Loaded policy from %s\n", sepolicy_file[policy_index]);
+
+	return 0;
+}
+
+int selinux_android_reload_policy(void)
+{
+    return selinux_android_load_policy_helper(true);
+}
+
+int selinux_android_load_policy(void)
+{
+	const char *mnt = SELINUXMNT;
+	int rc;
+	rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
+	if (rc < 0) {
+		if (errno == ENODEV) {
+			/* SELinux not enabled in kernel */
+			return -1;
+		}
+		if (errno == ENOENT) {
+			/* Fall back to legacy mountpoint. */
+			mnt = OLDSELINUXMNT;
+			rc = mkdir(mnt, 0755);
+			if (rc == -1 && errno != EEXIST) {
+				selinux_log(SELINUX_ERROR,"SELinux:  Could not mkdir:  %s\n",
+					strerror(errno));
+				return -1;
+			}
+			rc = mount(SELINUXFS, mnt, SELINUXFS, 0, NULL);
+		}
+	}
+	if (rc < 0) {
+		selinux_log(SELINUX_ERROR,"SELinux:  Could not mount selinuxfs:  %s\n",
+				strerror(errno));
+		return -1;
+	}
+	set_selinuxmnt(mnt);
+
+    return selinux_android_load_policy_helper(false);
+}
diff --git a/distrib/libselinux/src/avc.c b/distrib/libselinux/src/avc.c
new file mode 100644
index 0000000..76ca217
--- /dev/null
+++ b/distrib/libselinux/src/avc.c
@@ -0,0 +1,1090 @@
+/*
+ * Implementation of the userspace access vector cache (AVC).
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ *
+ * Derived from the kernel AVC implementation by
+ * Stephen Smalley <sds@epoch.ncsc.mil> and 
+ * James Morris <jmorris@redhat.com>.
+ */
+#include <selinux/avc.h>
+#include "selinux_internal.h"
+#include "avc_sidtab.h"
+#include "avc_internal.h"
+
+#define AVC_CACHE_SLOTS		512
+#define AVC_CACHE_MAXNODES	410
+
+struct avc_entry {
+	security_id_t ssid;
+	security_id_t tsid;
+	security_class_t tclass;
+	struct av_decision avd;
+	security_id_t	create_sid;
+	int used;		/* used recently */
+};
+
+struct avc_node {
+	struct avc_entry ae;
+	struct avc_node *next;
+};
+
+struct avc_cache {
+	struct avc_node *slots[AVC_CACHE_SLOTS];
+	uint32_t lru_hint;	/* LRU hint for reclaim scan */
+	uint32_t active_nodes;
+	uint32_t latest_notif;	/* latest revocation notification */
+};
+
+struct avc_callback_node {
+	int (*callback) (uint32_t event, security_id_t ssid,
+			 security_id_t tsid,
+			 security_class_t tclass, access_vector_t perms,
+			 access_vector_t * out_retained);
+	uint32_t events;
+	security_id_t ssid;
+	security_id_t tsid;
+	security_class_t tclass;
+	access_vector_t perms;
+	struct avc_callback_node *next;
+};
+
+static void *avc_netlink_thread = NULL;
+static void *avc_lock = NULL;
+static void *avc_log_lock = NULL;
+static struct avc_node *avc_node_freelist = NULL;
+static struct avc_cache avc_cache;
+static char *avc_audit_buf = NULL;
+static struct avc_cache_stats cache_stats;
+static struct avc_callback_node *avc_callbacks = NULL;
+static struct sidtab avc_sidtab;
+
+static inline int avc_hash(security_id_t ssid,
+			   security_id_t tsid, security_class_t tclass)
+{
+	return ((uintptr_t) ssid ^ ((uintptr_t) tsid << 2) ^ tclass)
+	    & (AVC_CACHE_SLOTS - 1);
+}
+
+int avc_context_to_sid(const char * ctx, security_id_t * sid)
+{
+	int rc;
+	avc_get_lock(avc_lock);
+	rc = sidtab_context_to_sid(&avc_sidtab, ctx, sid);
+	avc_release_lock(avc_lock);
+	return rc;
+}
+
+int avc_sid_to_context(security_id_t sid, char ** ctx)
+{
+	int rc;
+	*ctx = NULL;
+	avc_get_lock(avc_lock);
+	*ctx = strdup(sid->ctx);	/* caller must free via freecon */
+	rc = *ctx ? 0 : -1;
+	avc_release_lock(avc_lock);
+	return rc;
+}
+
+int avc_get_initial_sid(const char * name, security_id_t * sid)
+{
+	int rc;
+	char * con;
+
+	rc = security_get_initial_context(name, &con);
+	if (rc < 0)
+		return rc;
+	rc = avc_context_to_sid(con, sid);
+
+	freecon(con);
+
+	return rc;
+}
+
+int avc_open(struct selinux_opt *opts, unsigned nopts)
+{
+	avc_setenforce = 0;
+
+	while (nopts--)
+		switch(opts[nopts].type) {
+		case AVC_OPT_SETENFORCE:
+			avc_setenforce = 1;
+			avc_enforcing = !!opts[nopts].value;
+			break;
+		}
+
+	return avc_init("avc", NULL, NULL, NULL, NULL);
+}
+
+int avc_init(const char *prefix,
+	     const struct avc_memory_callback *mem_cb,
+	     const struct avc_log_callback *log_cb,
+	     const struct avc_thread_callback *thread_cb,
+	     const struct avc_lock_callback *lock_cb)
+{
+	struct avc_node *new;
+	int i, rc = 0;
+
+	if (prefix)
+		strncpy(avc_prefix, prefix, AVC_PREFIX_SIZE - 1);
+
+	set_callbacks(mem_cb, log_cb, thread_cb, lock_cb);
+
+	avc_lock = avc_alloc_lock();
+	avc_log_lock = avc_alloc_lock();
+
+	memset(&cache_stats, 0, sizeof(cache_stats));
+
+	for (i = 0; i < AVC_CACHE_SLOTS; i++)
+		avc_cache.slots[i] = 0;
+	avc_cache.lru_hint = 0;
+	avc_cache.active_nodes = 0;
+	avc_cache.latest_notif = 0;
+
+	rc = sidtab_init(&avc_sidtab);
+	if (rc) {
+		avc_log(SELINUX_ERROR,
+			"%s:  unable to initialize SID table\n",
+			avc_prefix);
+		goto out;
+	}
+
+	avc_audit_buf = (char *)avc_malloc(AVC_AUDIT_BUFSIZE);
+	if (!avc_audit_buf) {
+		avc_log(SELINUX_ERROR,
+			"%s:  unable to allocate audit buffer\n",
+			avc_prefix);
+		rc = -1;
+		goto out;
+	}
+
+	for (i = 0; i < AVC_CACHE_MAXNODES; i++) {
+		new = avc_malloc(sizeof(*new));
+		if (!new) {
+			avc_log(SELINUX_WARNING,
+				"%s:  warning: only got %d av entries\n",
+				avc_prefix, i);
+			break;
+		}
+		memset(new, 0, sizeof(*new));
+		new->next = avc_node_freelist;
+		avc_node_freelist = new;
+	}
+
+	if (!avc_setenforce) {
+		rc = security_getenforce();
+		if (rc < 0) {
+			avc_log(SELINUX_ERROR,
+				"%s:  could not determine enforcing mode: %s\n",
+				avc_prefix,
+				strerror(errno));
+			goto out;
+		}
+		avc_enforcing = rc;
+	}
+
+	rc = avc_netlink_open(0);
+	if (rc < 0) {
+		avc_log(SELINUX_ERROR,
+			"%s:  can't open netlink socket: %d (%s)\n",
+			avc_prefix, errno, strerror(errno));
+		goto out;
+	}
+	if (avc_using_threads) {
+		avc_netlink_thread = avc_create_thread(&avc_netlink_loop);
+		avc_netlink_trouble = 0;
+	}
+	avc_running = 1;
+      out:
+	return rc;
+}
+
+void avc_cache_stats(struct avc_cache_stats *p)
+{
+	memcpy(p, &cache_stats, sizeof(cache_stats));
+}
+
+void avc_sid_stats(void)
+{
+	avc_get_lock(avc_log_lock);
+	avc_get_lock(avc_lock);
+	sidtab_sid_stats(&avc_sidtab, avc_audit_buf, AVC_AUDIT_BUFSIZE);
+	avc_release_lock(avc_lock);
+	avc_log(SELINUX_INFO, "%s", avc_audit_buf);
+	avc_release_lock(avc_log_lock);
+}
+
+void avc_av_stats(void)
+{
+	int i, chain_len, max_chain_len, slots_used;
+	struct avc_node *node;
+
+	avc_get_lock(avc_lock);
+
+	slots_used = 0;
+	max_chain_len = 0;
+	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+		node = avc_cache.slots[i];
+		if (node) {
+			slots_used++;
+			chain_len = 0;
+			while (node) {
+				chain_len++;
+				node = node->next;
+			}
+			if (chain_len > max_chain_len)
+				max_chain_len = chain_len;
+		}
+	}
+
+	avc_release_lock(avc_lock);
+
+	avc_log(SELINUX_INFO, "%s:  %d AV entries and %d/%d buckets used, "
+		"longest chain length %d\n", avc_prefix,
+		avc_cache.active_nodes,
+		slots_used, AVC_CACHE_SLOTS, max_chain_len);
+}
+
+hidden_def(avc_av_stats)
+
+static inline struct avc_node *avc_reclaim_node(void)
+{
+	struct avc_node *prev, *cur;
+	int try;
+	uint32_t hvalue;
+
+	hvalue = avc_cache.lru_hint;
+	for (try = 0; try < 2; try++) {
+		do {
+			prev = NULL;
+			cur = avc_cache.slots[hvalue];
+			while (cur) {
+				if (!cur->ae.used)
+					goto found;
+
+				cur->ae.used = 0;
+
+				prev = cur;
+				cur = cur->next;
+			}
+			hvalue = (hvalue + 1) & (AVC_CACHE_SLOTS - 1);
+		} while (hvalue != avc_cache.lru_hint);
+	}
+
+	errno = ENOMEM;		/* this was a panic in the kernel... */
+	return NULL;
+
+      found:
+	avc_cache.lru_hint = hvalue;
+
+	if (prev == NULL)
+		avc_cache.slots[hvalue] = cur->next;
+	else
+		prev->next = cur->next;
+
+	return cur;
+}
+
+static inline void avc_clear_avc_entry(struct avc_entry *ae)
+{
+	memset(ae, 0, sizeof *ae);
+}
+
+static inline struct avc_node *avc_claim_node(security_id_t ssid,
+					      security_id_t tsid,
+					      security_class_t tclass)
+{
+	struct avc_node *new;
+	int hvalue;
+
+	if (!avc_node_freelist)
+		avc_cleanup();
+
+	if (avc_node_freelist) {
+		new = avc_node_freelist;
+		avc_node_freelist = avc_node_freelist->next;
+		avc_cache.active_nodes++;
+	} else {
+		new = avc_reclaim_node();
+		if (!new)
+			goto out;
+	}
+
+	hvalue = avc_hash(ssid, tsid, tclass);
+	avc_clear_avc_entry(&new->ae);
+	new->ae.used = 1;
+	new->ae.ssid = ssid;
+	new->ae.tsid = tsid;
+	new->ae.tclass = tclass;
+	new->next = avc_cache.slots[hvalue];
+	avc_cache.slots[hvalue] = new;
+
+      out:
+	return new;
+}
+
+static inline struct avc_node *avc_search_node(security_id_t ssid,
+					       security_id_t tsid,
+					       security_class_t tclass,
+					       int *probes)
+{
+	struct avc_node *cur;
+	int hvalue;
+	int tprobes = 1;
+
+	hvalue = avc_hash(ssid, tsid, tclass);
+	cur = avc_cache.slots[hvalue];
+	while (cur != NULL &&
+	       (ssid != cur->ae.ssid ||
+		tclass != cur->ae.tclass || tsid != cur->ae.tsid)) {
+		tprobes++;
+		cur = cur->next;
+	}
+
+	if (cur == NULL) {
+		/* cache miss */
+		goto out;
+	}
+
+	/* cache hit */
+	if (probes)
+		*probes = tprobes;
+
+	cur->ae.used = 1;
+
+      out:
+	return cur;
+}
+
+/**
+ * avc_lookup - Look up an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @requested: requested permissions, interpreted based on @tclass
+ * @aeref:  AVC entry reference
+ *
+ * Look up an AVC entry that is valid for the
+ * @requested permissions between the SID pair
+ * (@ssid, @tsid), interpreting the permissions
+ * based on @tclass.  If a valid AVC entry exists,
+ * then this function updates @aeref to refer to the
+ * entry and returns %0.  Otherwise, -1 is returned.
+ */
+static int avc_lookup(security_id_t ssid, security_id_t tsid,
+		      security_class_t tclass,
+		      access_vector_t requested, struct avc_entry_ref *aeref)
+{
+	struct avc_node *node;
+	int probes, rc = 0;
+
+	avc_cache_stats_incr(cav_lookups);
+	node = avc_search_node(ssid, tsid, tclass, &probes);
+
+	if (node && ((node->ae.avd.decided & requested) == requested)) {
+		avc_cache_stats_incr(cav_hits);
+		avc_cache_stats_add(cav_probes, probes);
+		aeref->ae = &node->ae;
+		goto out;
+	}
+
+	avc_cache_stats_incr(cav_misses);
+	rc = -1;
+      out:
+	return rc;
+}
+
+/**
+ * avc_insert - Insert an AVC entry.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ * @ae: AVC entry
+ * @aeref:  AVC entry reference
+ *
+ * Insert an AVC entry for the SID pair
+ * (@ssid, @tsid) and class @tclass.
+ * The access vectors and the sequence number are
+ * normally provided by the security server in
+ * response to a security_compute_av() call.  If the
+ * sequence number @ae->avd.seqno is not less than the latest
+ * revocation notification, then the function copies
+ * the access vectors into a cache entry, updates
+ * @aeref to refer to the entry, and returns %0.
+ * Otherwise, this function returns -%1 with @errno set to %EAGAIN.
+ */
+static int avc_insert(security_id_t ssid, security_id_t tsid,
+		      security_class_t tclass,
+		      struct avc_entry *ae, struct avc_entry_ref *aeref)
+{
+	struct avc_node *node;
+	int rc = 0;
+
+	if (ae->avd.seqno < avc_cache.latest_notif) {
+		avc_log(SELINUX_WARNING,
+			"%s:  seqno %d < latest_notif %d\n", avc_prefix,
+			ae->avd.seqno, avc_cache.latest_notif);
+		errno = EAGAIN;
+		rc = -1;
+		goto out;
+	}
+
+	node = avc_claim_node(ssid, tsid, tclass);
+	if (!node) {
+		rc = -1;
+		goto out;
+	}
+
+	memcpy(&node->ae.avd, &ae->avd, sizeof ae->avd);
+	aeref->ae = &node->ae;
+      out:
+	return rc;
+}
+
+void avc_cleanup(void)
+{
+}
+
+hidden_def(avc_cleanup)
+
+int avc_reset(void)
+{
+	struct avc_callback_node *c;
+	int i, ret, rc = 0, errsave = 0;
+	struct avc_node *node, *tmp;
+	errno = 0;
+
+	if (!avc_running)
+		return 0;
+
+	avc_get_lock(avc_lock);
+
+	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+		node = avc_cache.slots[i];
+		while (node) {
+			tmp = node;
+			node = node->next;
+			avc_clear_avc_entry(&tmp->ae);
+			tmp->next = avc_node_freelist;
+			avc_node_freelist = tmp;
+			avc_cache.active_nodes--;
+		}
+		avc_cache.slots[i] = 0;
+	}
+	avc_cache.lru_hint = 0;
+
+	avc_release_lock(avc_lock);
+
+	memset(&cache_stats, 0, sizeof(cache_stats));
+
+	for (c = avc_callbacks; c; c = c->next) {
+		if (c->events & AVC_CALLBACK_RESET) {
+			ret = c->callback(AVC_CALLBACK_RESET, 0, 0, 0, 0, 0);
+			if (ret && !rc) {
+				rc = ret;
+				errsave = errno;
+			}
+		}
+	}
+	errno = errsave;
+	return rc;
+}
+
+hidden_def(avc_reset)
+
+void avc_destroy(void)
+{
+	struct avc_callback_node *c;
+	struct avc_node *node, *tmp;
+	int i;
+
+	avc_get_lock(avc_lock);
+
+	if (avc_using_threads)
+		avc_stop_thread(avc_netlink_thread);
+	avc_netlink_close();
+
+	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+		node = avc_cache.slots[i];
+		while (node) {
+			tmp = node;
+			node = node->next;
+			avc_free(tmp);
+		}
+	}
+	while (avc_node_freelist) {
+		tmp = avc_node_freelist;
+		avc_node_freelist = tmp->next;
+		avc_free(tmp);
+	}
+	avc_release_lock(avc_lock);
+
+	while (avc_callbacks) {
+		c = avc_callbacks;
+		avc_callbacks = c->next;
+		avc_free(c);
+	}
+	sidtab_destroy(&avc_sidtab);
+	avc_free_lock(avc_lock);
+	avc_free_lock(avc_log_lock);
+	avc_free(avc_audit_buf);
+	avc_running = 0;
+}
+
+/* ratelimit stuff put aside for now --EFW */
+#if 0
+/*
+ * Copied from net/core/utils.c:net_ratelimit and modified for
+ * use by the AVC audit facility.
+ */
+#define AVC_MSG_COST	5*HZ
+#define AVC_MSG_BURST	10*5*HZ
+
+/*
+ * This enforces a rate limit: not more than one kernel message
+ * every 5secs to make a denial-of-service attack impossible.
+ */
+static int avc_ratelimit(void)
+{
+	static unsigned long toks = 10 * 5 * HZ;
+	static unsigned long last_msg;
+	static int missed, rc = 0;
+	unsigned long now = jiffies;
+	void *ratelimit_lock = avc_alloc_lock();
+
+	avc_get_lock(ratelimit_lock);
+	toks += now - last_msg;
+	last_msg = now;
+	if (toks > AVC_MSG_BURST)
+		toks = AVC_MSG_BURST;
+	if (toks >= AVC_MSG_COST) {
+		int lost = missed;
+		missed = 0;
+		toks -= AVC_MSG_COST;
+		avc_release_lock(ratelimit_lock);
+		if (lost) {
+			avc_log(SELINUX_WARNING,
+				"%s:  %d messages suppressed.\n", avc_prefix,
+				lost);
+		}
+		rc = 1;
+		goto out;
+	}
+	missed++;
+	avc_release_lock(ratelimit_lock);
+      out:
+	avc_free_lock(ratelimit_lock);
+	return rc;
+}
+
+static inline int check_avc_ratelimit(void)
+{
+	if (avc_enforcing)
+		return avc_ratelimit();
+	else {
+		/* If permissive, then never suppress messages. */
+		return 1;
+	}
+}
+#endif				/* ratelimit stuff */
+
+/**
+ * avc_dump_av - Display an access vector in human-readable form.
+ * @tclass: target security class
+ * @av: access vector
+ */
+static void avc_dump_av(security_class_t tclass, access_vector_t av)
+{
+	const char *permstr;
+	access_vector_t bit = 1;
+
+	if (av == 0) {
+		log_append(avc_audit_buf, " null");
+		return;
+	}
+
+	log_append(avc_audit_buf, " {");
+
+	while (av) {
+		if (av & bit) {
+			permstr = security_av_perm_to_string(tclass, bit);
+			if (!permstr)
+				break;
+			log_append(avc_audit_buf, " %s", permstr);
+			av &= ~bit;
+		}
+		bit <<= 1;
+	}
+
+	if (av)
+		log_append(avc_audit_buf, " 0x%x", av);
+	log_append(avc_audit_buf, " }");
+}
+
+/**
+ * avc_dump_query - Display a SID pair and a class in human-readable form.
+ * @ssid: source security identifier
+ * @tsid: target security identifier
+ * @tclass: target security class
+ */
+static void avc_dump_query(security_id_t ssid, security_id_t tsid,
+			   security_class_t tclass)
+{
+	avc_get_lock(avc_lock);
+
+	log_append(avc_audit_buf, "scontext=%s tcontext=%s",
+		   ssid->ctx, tsid->ctx);
+
+	avc_release_lock(avc_lock);
+	log_append(avc_audit_buf, " tclass=%s",
+		   security_class_to_string(tclass));
+}
+
+void avc_audit(security_id_t ssid, security_id_t tsid,
+	       security_class_t tclass, access_vector_t requested,
+	       struct av_decision *avd, int result, void *a)
+{
+	access_vector_t denied, audited;
+
+	denied = requested & ~avd->allowed;
+	if (denied)
+		audited = denied & avd->auditdeny;
+	else if (!requested || result)
+		audited = denied = requested;
+	else
+		audited = requested & avd->auditallow;
+	if (!audited)
+		return;
+#if 0
+	if (!check_avc_ratelimit())
+		return;
+#endif
+	/* prevent overlapping buffer writes */
+	avc_get_lock(avc_log_lock);
+	snprintf(avc_audit_buf, AVC_AUDIT_BUFSIZE,
+		 "%s:  %s ", avc_prefix, (denied || !requested) ? "denied" : "granted");
+	avc_dump_av(tclass, audited);
+	log_append(avc_audit_buf, " for ");
+
+	/* get any extra information printed by the callback */
+	avc_suppl_audit(a, tclass, avc_audit_buf + strlen(avc_audit_buf),
+			AVC_AUDIT_BUFSIZE - strlen(avc_audit_buf));
+
+	log_append(avc_audit_buf, " ");
+	avc_dump_query(ssid, tsid, tclass);
+	log_append(avc_audit_buf, "\n");
+	avc_log(SELINUX_AVC, "%s", avc_audit_buf);
+
+	avc_release_lock(avc_log_lock);
+}
+
+hidden_def(avc_audit)
+
+int avc_has_perm_noaudit(security_id_t ssid,
+			 security_id_t tsid,
+			 security_class_t tclass,
+			 access_vector_t requested,
+			 struct avc_entry_ref *aeref, struct av_decision *avd)
+{
+	struct avc_entry *ae;
+	int rc = 0;
+	struct avc_entry entry;
+	access_vector_t denied;
+	struct avc_entry_ref ref;
+
+	if (!avc_using_threads && !avc_app_main_loop) {
+		(void)avc_netlink_check_nb();
+	}
+
+	if (!aeref) {
+		avc_entry_ref_init(&ref);
+		aeref = &ref;
+	}
+
+	avc_get_lock(avc_lock);
+	avc_cache_stats_incr(entry_lookups);
+	ae = aeref->ae;
+	if (ae) {
+		if (ae->ssid == ssid &&
+		    ae->tsid == tsid &&
+		    ae->tclass == tclass &&
+		    ((ae->avd.decided & requested) == requested)) {
+			avc_cache_stats_incr(entry_hits);
+			ae->used = 1;
+		} else {
+			avc_cache_stats_incr(entry_discards);
+			ae = 0;
+		}
+	}
+
+	if (!ae) {
+		avc_cache_stats_incr(entry_misses);
+		rc = avc_lookup(ssid, tsid, tclass, requested, aeref);
+		if (rc) {
+			rc = security_compute_av(ssid->ctx, tsid->ctx,
+						 tclass, requested,
+						 &entry.avd);
+			if (rc)
+				goto out;
+			rc = avc_insert(ssid, tsid, tclass, &entry, aeref);
+			if (rc)
+				goto out;
+		}
+		ae = aeref->ae;
+	}
+
+	if (avd)
+		memcpy(avd, &ae->avd, sizeof(*avd));
+
+	denied = requested & ~(ae->avd.allowed);
+
+	if (!requested || denied) {
+		if (!avc_enforcing ||
+		    (ae->avd.flags & SELINUX_AVD_FLAGS_PERMISSIVE))
+			ae->avd.allowed |= requested;
+		else {
+			errno = EACCES;
+			rc = -1;
+		}
+	}
+
+      out:
+	avc_release_lock(avc_lock);
+	return rc;
+}
+
+hidden_def(avc_has_perm_noaudit)
+
+int avc_has_perm(security_id_t ssid, security_id_t tsid,
+		 security_class_t tclass, access_vector_t requested,
+		 struct avc_entry_ref *aeref, void *auditdata)
+{
+	struct av_decision avd;
+	int errsave, rc;
+
+	memset(&avd, 0, sizeof(avd));
+
+	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, aeref, &avd);
+	errsave = errno;
+	avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
+	errno = errsave;
+	return rc;
+}
+
+int avc_compute_create(security_id_t ssid,  security_id_t tsid,
+		       security_class_t tclass, security_id_t *newsid)
+{
+	int rc;
+	struct avc_entry_ref aeref;
+	struct avc_entry entry;
+	char * ctx;
+
+	*newsid = NULL;
+	avc_entry_ref_init(&aeref);
+
+	avc_get_lock(avc_lock);
+
+	/* check for a cached entry */
+	rc = avc_lookup(ssid, tsid, tclass, 0, &aeref);
+	if (rc) {
+		/* need to make a cache entry for this tuple */
+		rc = security_compute_av(ssid->ctx, tsid->ctx,
+					 tclass, 0, &entry.avd);
+		if (rc)
+			goto out;
+		rc = avc_insert(ssid, tsid, tclass, &entry, &aeref);
+		if (rc)
+			goto out;
+	}
+
+	/* check for a saved compute_create value */
+	if (!aeref.ae->create_sid) {
+		/* need to query the kernel policy */
+		rc = security_compute_create(ssid->ctx, tsid->ctx, tclass,
+						 &ctx);
+		if (rc)
+			goto out;
+		rc = sidtab_context_to_sid(&avc_sidtab, ctx, newsid);
+		freecon(ctx);
+		if (rc)
+			goto out;
+
+		aeref.ae->create_sid = *newsid;
+	} else {
+		/* found saved value */
+		*newsid = aeref.ae->create_sid;
+	}
+
+	rc = 0;
+out:
+	avc_release_lock(avc_lock);
+	return rc;
+}
+
+int avc_add_callback(int (*callback) (uint32_t event, security_id_t ssid,
+				      security_id_t tsid,
+				      security_class_t tclass,
+				      access_vector_t perms,
+				      access_vector_t * out_retained),
+		     uint32_t events, security_id_t ssid,
+		     security_id_t tsid,
+		     security_class_t tclass, access_vector_t perms)
+{
+	struct avc_callback_node *c;
+	int rc = 0;
+
+	c = avc_malloc(sizeof(*c));
+	if (!c) {
+		rc = -1;
+		goto out;
+	}
+
+	c->callback = callback;
+	c->events = events;
+	c->ssid = ssid;
+	c->tsid = tsid;
+	c->tclass = tclass;
+	c->perms = perms;
+	c->next = avc_callbacks;
+	avc_callbacks = c;
+      out:
+	return rc;
+}
+
+static inline int avc_sidcmp(security_id_t x, security_id_t y)
+{
+	return (x == y || x == SECSID_WILD || y == SECSID_WILD);
+}
+
+static inline void avc_update_node(uint32_t event, struct avc_node *node,
+				   access_vector_t perms)
+{
+	switch (event) {
+	case AVC_CALLBACK_GRANT:
+		node->ae.avd.allowed |= perms;
+		break;
+	case AVC_CALLBACK_TRY_REVOKE:
+	case AVC_CALLBACK_REVOKE:
+		node->ae.avd.allowed &= ~perms;
+		break;
+	case AVC_CALLBACK_AUDITALLOW_ENABLE:
+		node->ae.avd.auditallow |= perms;
+		break;
+	case AVC_CALLBACK_AUDITALLOW_DISABLE:
+		node->ae.avd.auditallow &= ~perms;
+		break;
+	case AVC_CALLBACK_AUDITDENY_ENABLE:
+		node->ae.avd.auditdeny |= perms;
+		break;
+	case AVC_CALLBACK_AUDITDENY_DISABLE:
+		node->ae.avd.auditdeny &= ~perms;
+		break;
+	}
+}
+
+static int avc_update_cache(uint32_t event, security_id_t ssid,
+			    security_id_t tsid, security_class_t tclass,
+			    access_vector_t perms)
+{
+	struct avc_node *node;
+	int i;
+
+	avc_get_lock(avc_lock);
+
+	if (ssid == SECSID_WILD || tsid == SECSID_WILD) {
+		/* apply to all matching nodes */
+		for (i = 0; i < AVC_CACHE_SLOTS; i++) {
+			for (node = avc_cache.slots[i]; node; node = node->next) {
+				if (avc_sidcmp(ssid, node->ae.ssid) &&
+				    avc_sidcmp(tsid, node->ae.tsid) &&
+				    tclass == node->ae.tclass) {
+					avc_update_node(event, node, perms);
+				}
+			}
+		}
+	} else {
+		/* apply to one node */
+		node = avc_search_node(ssid, tsid, tclass, 0);
+		if (node) {
+			avc_update_node(event, node, perms);
+		}
+	}
+
+	avc_release_lock(avc_lock);
+
+	return 0;
+}
+
+/* avc_control - update cache and call callbacks
+ *
+ * This should not be called directly; use the individual event
+ * functions instead.
+ */
+static int avc_control(uint32_t event, security_id_t ssid,
+		       security_id_t tsid, security_class_t tclass,
+		       access_vector_t perms,
+		       uint32_t seqno, access_vector_t * out_retained)
+{
+	struct avc_callback_node *c;
+	access_vector_t tretained = 0, cretained = 0;
+	int ret, rc = 0, errsave = 0;
+	errno = 0;
+
+	/*
+	 * try_revoke only removes permissions from the cache
+	 * state if they are not retained by the object manager.
+	 * Hence, try_revoke must wait until after the callbacks have
+	 * been invoked to update the cache state.
+	 */
+	if (event != AVC_CALLBACK_TRY_REVOKE)
+		avc_update_cache(event, ssid, tsid, tclass, perms);
+
+	for (c = avc_callbacks; c; c = c->next) {
+		if ((c->events & event) &&
+		    avc_sidcmp(c->ssid, ssid) &&
+		    avc_sidcmp(c->tsid, tsid) &&
+		    c->tclass == tclass && (c->perms & perms)) {
+			cretained = 0;
+			ret = c->callback(event, ssid, tsid, tclass,
+					  (c->perms & perms), &cretained);
+			if (ret && !rc) {
+				rc = ret;
+				errsave = errno;
+			}
+			if (!ret)
+				tretained |= cretained;
+		}
+	}
+
+	if (event == AVC_CALLBACK_TRY_REVOKE) {
+		/* revoke any unretained permissions */
+		perms &= ~tretained;
+		avc_update_cache(event, ssid, tsid, tclass, perms);
+		*out_retained = tretained;
+	}
+
+	avc_get_lock(avc_lock);
+	if (seqno > avc_cache.latest_notif)
+		avc_cache.latest_notif = seqno;
+	avc_release_lock(avc_lock);
+
+	errno = errsave;
+	return rc;
+}
+
+/**
+ * avc_ss_grant - Grant previously denied permissions.
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions to grant
+ * @seqno: policy sequence number
+ */
+int avc_ss_grant(security_id_t ssid, security_id_t tsid,
+		 security_class_t tclass, access_vector_t perms,
+		 uint32_t seqno)
+{
+	return avc_control(AVC_CALLBACK_GRANT,
+			   ssid, tsid, tclass, perms, seqno, 0);
+}
+
+/**
+ * avc_ss_try_revoke - Try to revoke previously granted permissions.
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions to grant
+ * @seqno: policy sequence number
+ * @out_retained: subset of @perms that are retained
+ *
+ * Try to revoke previously granted permissions, but
+ * only if they are not retained as migrated permissions.
+ * Return the subset of permissions that are retained via @out_retained.
+ */
+int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid,
+		      security_class_t tclass,
+		      access_vector_t perms, uint32_t seqno,
+		      access_vector_t * out_retained)
+{
+	return avc_control(AVC_CALLBACK_TRY_REVOKE,
+			   ssid, tsid, tclass, perms, seqno, out_retained);
+}
+
+/**
+ * avc_ss_revoke - Revoke previously granted permissions.
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions to grant
+ * @seqno: policy sequence number
+ *
+ * Revoke previously granted permissions, even if
+ * they are retained as migrated permissions.
+ */
+int avc_ss_revoke(security_id_t ssid, security_id_t tsid,
+		  security_class_t tclass, access_vector_t perms,
+		  uint32_t seqno)
+{
+	return avc_control(AVC_CALLBACK_REVOKE,
+			   ssid, tsid, tclass, perms, seqno, 0);
+}
+
+/**
+ * avc_ss_reset - Flush the cache and revalidate migrated permissions.
+ * @seqno: policy sequence number
+ */
+int avc_ss_reset(uint32_t seqno)
+{
+	int rc;
+
+	rc = avc_reset();
+
+	avc_get_lock(avc_lock);
+	if (seqno > avc_cache.latest_notif)
+		avc_cache.latest_notif = seqno;
+	avc_release_lock(avc_lock);
+
+	return rc;
+}
+
+/**
+ * avc_ss_set_auditallow - Enable or disable auditing of granted permissions.
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions to grant
+ * @seqno: policy sequence number
+ * @enable: enable flag.
+ */
+int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid,
+			  security_class_t tclass, access_vector_t perms,
+			  uint32_t seqno, uint32_t enable)
+{
+	if (enable)
+		return avc_control(AVC_CALLBACK_AUDITALLOW_ENABLE,
+				   ssid, tsid, tclass, perms, seqno, 0);
+	else
+		return avc_control(AVC_CALLBACK_AUDITALLOW_DISABLE,
+				   ssid, tsid, tclass, perms, seqno, 0);
+}
+
+/**
+ * avc_ss_set_auditdeny - Enable or disable auditing of denied permissions.
+ * @ssid: source security identifier or %SECSID_WILD
+ * @tsid: target security identifier or %SECSID_WILD
+ * @tclass: target security class
+ * @perms: permissions to grant
+ * @seqno: policy sequence number
+ * @enable: enable flag.
+ */
+int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid,
+			 security_class_t tclass, access_vector_t perms,
+			 uint32_t seqno, uint32_t enable)
+{
+	if (enable)
+		return avc_control(AVC_CALLBACK_AUDITDENY_ENABLE,
+				   ssid, tsid, tclass, perms, seqno, 0);
+	else
+		return avc_control(AVC_CALLBACK_AUDITDENY_DISABLE,
+				   ssid, tsid, tclass, perms, seqno, 0);
+}
diff --git a/distrib/libselinux/src/avc_internal.c b/distrib/libselinux/src/avc_internal.c
new file mode 100644
index 0000000..d219331
--- /dev/null
+++ b/distrib/libselinux/src/avc_internal.c
@@ -0,0 +1,293 @@
+/*
+ * Callbacks for user-supplied memory allocation, supplemental
+ * auditing, and locking routines.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ *
+ * Netlink code derived in part from sample code by
+ * James Morris <jmorris@redhat.com>.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/types.h>
+#include <linux/netlink.h>
+#include "callbacks.h"
+#include "selinux_netlink.h"
+#include "avc_internal.h"
+
+#ifndef NETLINK_SELINUX
+#define NETLINK_SELINUX 7
+#endif
+
+/* callback pointers */
+void *(*avc_func_malloc) (size_t) = NULL;
+void (*avc_func_free) (void *) = NULL;
+
+void (*avc_func_log) (const char *, ...) = NULL;
+void (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL;
+
+int avc_using_threads = 0;
+int avc_app_main_loop = 0;
+void *(*avc_func_create_thread) (void (*)(void)) = NULL;
+void (*avc_func_stop_thread) (void *) = NULL;
+
+void *(*avc_func_alloc_lock) (void) = NULL;
+void (*avc_func_get_lock) (void *) = NULL;
+void (*avc_func_release_lock) (void *) = NULL;
+void (*avc_func_free_lock) (void *) = NULL;
+
+/* message prefix string and avc enforcing mode */
+char avc_prefix[AVC_PREFIX_SIZE] = "uavc";
+int avc_running = 0;
+int avc_enforcing = 1;
+int avc_setenforce = 0;
+int avc_netlink_trouble = 0;
+
+/* netlink socket code */
+static int fd = -1;
+
+int avc_netlink_open(int blocking)
+{
+	int len, rc = 0;
+	struct sockaddr_nl addr;
+
+	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
+	if (fd < 0) {
+		rc = fd;
+		goto out;
+	}
+	
+	fcntl(fd, F_SETFD, FD_CLOEXEC);
+	if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) {
+		close(fd);
+		fd = -1;
+		rc = -1;
+		goto out;
+	}
+
+	len = sizeof(addr);
+
+	memset(&addr, 0, len);
+	addr.nl_family = AF_NETLINK;
+	addr.nl_groups = SELNL_GRP_AVC;
+
+	if (bind(fd, (struct sockaddr *)&addr, len) < 0) {
+		close(fd);
+		fd = -1;
+		rc = -1;
+		goto out;
+	}
+      out:
+	return rc;
+}
+
+void avc_netlink_close(void)
+{
+	if (fd >= 0)
+		close(fd);
+	fd = -1;	
+}
+
+static int avc_netlink_receive(char *buf, unsigned buflen, int blocking)
+{
+	int rc;
+	struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
+	struct sockaddr_nl nladdr;
+	socklen_t nladdrlen = sizeof nladdr;
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+
+	do {
+		rc = poll(&pfd, 1, (blocking ? -1 : 0));
+	} while (rc < 0 && errno == EINTR);
+
+	if (rc == 0 && !blocking) {
+		errno = EWOULDBLOCK;
+		return -1;
+	}
+	else if (rc < 1) {
+		avc_log(SELINUX_ERROR, "%s:  netlink poll: error %d\n",
+			avc_prefix, errno);
+		return rc;
+	}
+
+	rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr,
+		      &nladdrlen);
+	if (rc < 0)
+		return rc;
+
+	if (nladdrlen != sizeof nladdr) {
+		avc_log(SELINUX_WARNING,
+			"%s:  warning: netlink address truncated, len %d?\n",
+			avc_prefix, nladdrlen);
+		return -1;
+	}
+
+	if (nladdr.nl_pid) {
+		avc_log(SELINUX_WARNING,
+			"%s:  warning: received spoofed netlink packet from: %d\n",
+			avc_prefix, nladdr.nl_pid);
+		return -1;
+	}
+
+	if (rc == 0) {
+		avc_log(SELINUX_WARNING,
+			"%s:  warning: received EOF on netlink socket\n",
+			avc_prefix);
+		errno = EBADFD;
+		return -1;
+	}
+
+	if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) {
+		avc_log(SELINUX_WARNING,
+			"%s:  warning: incomplete netlink message\n",
+			avc_prefix);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int avc_netlink_process(char *buf)
+{
+	int rc;
+	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
+
+	switch (nlh->nlmsg_type) {
+	case NLMSG_ERROR:{
+		struct nlmsgerr *err = NLMSG_DATA(nlh);
+
+		/* Netlink ack */
+		if (err->error == 0)
+			break;
+
+		errno = -err->error;
+		avc_log(SELINUX_ERROR,
+			"%s:  netlink error: %d\n", avc_prefix, errno);
+		return -1;
+	}
+
+	case SELNL_MSG_SETENFORCE:{
+		struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
+		avc_log(SELINUX_INFO,
+			"%s:  received setenforce notice (enforcing=%d)\n",
+			avc_prefix, msg->val);
+		if (avc_setenforce)
+			break;
+		avc_enforcing = msg->val;
+		if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) {
+			avc_log(SELINUX_ERROR,
+				"%s:  cache reset returned %d (errno %d)\n",
+				avc_prefix, rc, errno);
+			return rc;
+		}
+		rc = selinux_netlink_setenforce(msg->val);
+		if (rc < 0)
+			return rc;
+		break;
+	}
+
+	case SELNL_MSG_POLICYLOAD:{
+		struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
+		avc_log(SELINUX_INFO,
+			"%s:  received policyload notice (seqno=%d)\n",
+			avc_prefix, msg->seqno);
+		rc = avc_ss_reset(msg->seqno);
+		if (rc < 0) {
+			avc_log(SELINUX_ERROR,
+				"%s:  cache reset returned %d (errno %d)\n",
+				avc_prefix, rc, errno);
+			return rc;
+		}
+		rc = selinux_netlink_policyload(msg->seqno);
+		if (rc < 0)
+			return rc;
+		break;
+	}
+
+	default:
+		avc_log(SELINUX_WARNING,
+			"%s:  warning: unknown netlink message %d\n",
+			avc_prefix, nlh->nlmsg_type);
+	}
+	return 0;
+}
+
+int avc_netlink_check_nb(void)
+{
+	int rc;
+	char buf[1024] __attribute__ ((aligned));
+
+	while (1) {
+		errno = 0;
+		rc = avc_netlink_receive(buf, sizeof(buf), 0);
+		if (rc < 0) {
+			if (errno == EWOULDBLOCK)
+				return 0;
+			if (errno == 0 || errno == EINTR)
+				continue;
+			else {
+				avc_log(SELINUX_ERROR,
+					"%s:  netlink recvfrom: error %d\n",
+					avc_prefix, errno);
+				return rc;
+			}
+		}
+
+		(void)avc_netlink_process(buf);
+	}
+	return 0;
+}
+
+/* run routine for the netlink listening thread */
+void avc_netlink_loop(void)
+{
+	int rc;
+	char buf[1024] __attribute__ ((aligned));
+
+	while (1) {
+		errno = 0;
+		rc = avc_netlink_receive(buf, sizeof(buf), 1);
+		if (rc < 0) {
+			if (errno == 0 || errno == EINTR)
+				continue;
+			else {
+				avc_log(SELINUX_ERROR,
+					"%s:  netlink recvfrom: error %d\n",
+					avc_prefix, errno);
+				break;
+			}
+		}
+
+		rc = avc_netlink_process(buf);
+		if (rc < 0)
+			break;
+	}
+
+	close(fd);
+	fd = -1;
+	avc_netlink_trouble = 1;
+	avc_log(SELINUX_ERROR,
+		"%s:  netlink thread: errors encountered, terminating\n",
+		avc_prefix);
+}
+
+int avc_netlink_acquire_fd(void)
+{
+    avc_app_main_loop = 1;
+
+    return fd;
+}
+
+void avc_netlink_release_fd(void)
+{
+    avc_app_main_loop = 0;
+}
diff --git a/distrib/libselinux/src/avc_internal.h b/distrib/libselinux/src/avc_internal.h
new file mode 100644
index 0000000..53610e8
--- /dev/null
+++ b/distrib/libselinux/src/avc_internal.h
@@ -0,0 +1,182 @@
+/*
+ * This file describes the internal interface used by the AVC
+ * for calling the user-supplied memory allocation, supplemental
+ * auditing, and locking routine, as well as incrementing the
+ * statistics fields.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+#ifndef _SELINUX_AVC_INTERNAL_H_
+#define _SELINUX_AVC_INTERNAL_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <selinux/avc.h>
+#include "callbacks.h"
+#include "dso.h"
+
+/* callback pointers */
+extern void *(*avc_func_malloc) (size_t) hidden;
+extern void (*avc_func_free) (void *)hidden;
+
+extern void (*avc_func_log) (const char *, ...)hidden;
+extern void (*avc_func_audit) (void *, security_class_t, char *, size_t)hidden;
+
+extern int avc_using_threads hidden;
+extern int avc_app_main_loop hidden;
+extern void *(*avc_func_create_thread) (void (*)(void))hidden;
+extern void (*avc_func_stop_thread) (void *)hidden;
+
+extern void *(*avc_func_alloc_lock) (void)hidden;
+extern void (*avc_func_get_lock) (void *)hidden;
+extern void (*avc_func_release_lock) (void *)hidden;
+extern void (*avc_func_free_lock) (void *)hidden;
+
+static inline void set_callbacks(const struct avc_memory_callback *mem_cb,
+				 const struct avc_log_callback *log_cb,
+				 const struct avc_thread_callback *thread_cb,
+				 const struct avc_lock_callback *lock_cb)
+{
+	if (mem_cb) {
+		avc_func_malloc = mem_cb->func_malloc;
+		avc_func_free = mem_cb->func_free;
+	}
+	if (log_cb) {
+		avc_func_log = log_cb->func_log;
+		avc_func_audit = log_cb->func_audit;
+	}
+	if (thread_cb) {
+		avc_using_threads = 1;
+		avc_func_create_thread = thread_cb->func_create_thread;
+		avc_func_stop_thread = thread_cb->func_stop_thread;
+	}
+	if (lock_cb) {
+		avc_func_alloc_lock = lock_cb->func_alloc_lock;
+		avc_func_get_lock = lock_cb->func_get_lock;
+		avc_func_release_lock = lock_cb->func_release_lock;
+		avc_func_free_lock = lock_cb->func_free_lock;
+	}
+}
+
+/* message prefix and enforcing mode*/
+#define AVC_PREFIX_SIZE 16
+extern char avc_prefix[AVC_PREFIX_SIZE] hidden;
+extern int avc_running hidden;
+extern int avc_enforcing hidden;
+extern int avc_setenforce hidden;
+
+/* user-supplied callback interface for avc */
+static inline void *avc_malloc(size_t size)
+{
+	return avc_func_malloc ? avc_func_malloc(size) : malloc(size);
+}
+
+static inline void avc_free(void *ptr)
+{
+	if (avc_func_free)
+		avc_func_free(ptr);
+	else
+		free(ptr);
+}
+
+/* this is a macro in order to use the variadic capability. */
+#define avc_log(type, format...) \
+  if (avc_func_log) \
+    avc_func_log(format); \
+  else \
+    selinux_log(type, format);
+
+static inline void avc_suppl_audit(void *ptr, security_class_t class,
+				   char *buf, size_t len)
+{
+	if (avc_func_audit)
+		avc_func_audit(ptr, class, buf, len);
+	else
+		selinux_audit(ptr, class, buf, len);
+}
+
+static inline void *avc_create_thread(void (*run) (void))
+{
+	return avc_func_create_thread ? avc_func_create_thread(run) : NULL;
+}
+
+static inline void avc_stop_thread(void *thread)
+{
+	if (avc_func_stop_thread)
+		avc_func_stop_thread(thread);
+}
+
+static inline void *avc_alloc_lock(void)
+{
+	return avc_func_alloc_lock ? avc_func_alloc_lock() : NULL;
+}
+
+static inline void avc_get_lock(void *lock)
+{
+	if (avc_func_get_lock)
+		avc_func_get_lock(lock);
+}
+
+static inline void avc_release_lock(void *lock)
+{
+	if (avc_func_release_lock)
+		avc_func_release_lock(lock);
+}
+
+static inline void avc_free_lock(void *lock)
+{
+	if (avc_func_free_lock)
+		avc_func_free_lock(lock);
+}
+
+/* statistics helper routines */
+#ifdef AVC_CACHE_STATS
+
+#define avc_cache_stats_incr(field) \
+  cache_stats.field ++;
+#define avc_cache_stats_add(field, num) \
+  cache_stats.field += num;
+
+#else
+
+#define avc_cache_stats_incr(field)
+#define avc_cache_stats_add(field, num)
+
+#endif
+
+/* logging helper routines */
+#define AVC_AUDIT_BUFSIZE 1024
+
+/* again, we need the variadic capability here */
+#define log_append(buf,format...) \
+  snprintf(buf+strlen(buf), AVC_AUDIT_BUFSIZE-strlen(buf), format)
+
+/* internal callbacks */
+int avc_ss_grant(security_id_t ssid, security_id_t tsid,
+		 security_class_t tclass, access_vector_t perms,
+		 uint32_t seqno) hidden;
+int avc_ss_try_revoke(security_id_t ssid, security_id_t tsid,
+		      security_class_t tclass,
+		      access_vector_t perms, uint32_t seqno,
+		      access_vector_t * out_retained) hidden;
+int avc_ss_revoke(security_id_t ssid, security_id_t tsid,
+		  security_class_t tclass, access_vector_t perms,
+		  uint32_t seqno) hidden;
+int avc_ss_reset(uint32_t seqno) hidden;
+int avc_ss_set_auditallow(security_id_t ssid, security_id_t tsid,
+			  security_class_t tclass, access_vector_t perms,
+			  uint32_t seqno, uint32_t enable) hidden;
+int avc_ss_set_auditdeny(security_id_t ssid, security_id_t tsid,
+			 security_class_t tclass, access_vector_t perms,
+			 uint32_t seqno, uint32_t enable) hidden;
+
+/* netlink kernel message code */
+extern int avc_netlink_trouble hidden;
+
+hidden_proto(avc_av_stats)
+    hidden_proto(avc_cleanup)
+    hidden_proto(avc_reset)
+    hidden_proto(avc_audit)
+    hidden_proto(avc_has_perm_noaudit)
+#endif				/* _SELINUX_AVC_INTERNAL_H_ */
diff --git a/distrib/libselinux/src/avc_sidtab.c b/distrib/libselinux/src/avc_sidtab.c
new file mode 100644
index 0000000..52f21df
--- /dev/null
+++ b/distrib/libselinux/src/avc_sidtab.c
@@ -0,0 +1,152 @@
+/*
+ * Implementation of the userspace SID hashtable.
+ *
+ * Author : Eamon Walsh, <ewalsh@epoch.ncsc.mil>
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include <selinux/avc.h>
+#include "avc_sidtab.h"
+#include "avc_internal.h"
+
+static inline unsigned sidtab_hash(const char * key)
+{
+	char *p, *keyp;
+	unsigned int size;
+	unsigned int val;
+
+	val = 0;
+	keyp = (char *)key;
+	size = strlen(keyp);
+	for (p = keyp; (unsigned int)(p - keyp) < size; p++)
+		val =
+		    (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^ (*p);
+	return val & (SIDTAB_SIZE - 1);
+}
+
+int sidtab_init(struct sidtab *s)
+{
+	int i, rc = 0;
+
+	s->htable = (struct sidtab_node **)avc_malloc
+	    (sizeof(struct sidtab_node *) * SIDTAB_SIZE);
+
+	if (!s->htable) {
+		rc = -1;
+		goto out;
+	}
+	for (i = 0; i < SIDTAB_SIZE; i++)
+		s->htable[i] = NULL;
+	s->nel = 0;
+      out:
+	return rc;
+}
+
+int sidtab_insert(struct sidtab *s, const char * ctx)
+{
+	int hvalue, rc = 0;
+	struct sidtab_node *newnode;
+	char * newctx;
+
+	newnode = (struct sidtab_node *)avc_malloc(sizeof(*newnode));
+	if (!newnode) {
+		rc = -1;
+		goto out;
+	}
+	newctx = (char *) strdup(ctx);
+	if (!newctx) {
+		rc = -1;
+		avc_free(newnode);
+		goto out;
+	}
+
+	hvalue = sidtab_hash(newctx);
+	newnode->next = s->htable[hvalue];
+	newnode->sid_s.ctx = newctx;
+	newnode->sid_s.refcnt = 1;	/* unused */
+	s->htable[hvalue] = newnode;
+	s->nel++;
+      out:
+	return rc;
+}
+
+int
+sidtab_context_to_sid(struct sidtab *s,
+		      const char * ctx, security_id_t * sid)
+{
+	int hvalue, rc = 0;
+	struct sidtab_node *cur;
+
+	*sid = NULL;
+	hvalue = sidtab_hash(ctx);
+
+      loop:
+	cur = s->htable[hvalue];
+	while (cur != NULL && strcmp(cur->sid_s.ctx, ctx))
+		cur = cur->next;
+
+	if (cur == NULL) {	/* need to make a new entry */
+		rc = sidtab_insert(s, ctx);
+		if (rc)
+			goto out;
+		goto loop;	/* find the newly inserted node */
+	}
+
+	*sid = &cur->sid_s;
+      out:
+	return rc;
+}
+
+void sidtab_sid_stats(struct sidtab *h, char *buf, int buflen)
+{
+	int i, chain_len, slots_used, max_chain_len;
+	struct sidtab_node *cur;
+
+	slots_used = 0;
+	max_chain_len = 0;
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = h->htable[i];
+		if (cur) {
+			slots_used++;
+			chain_len = 0;
+			while (cur) {
+				chain_len++;
+				cur = cur->next;
+			}
+
+			if (chain_len > max_chain_len)
+				max_chain_len = chain_len;
+		}
+	}
+
+	snprintf(buf, buflen,
+		 "%s:  %d SID entries and %d/%d buckets used, longest "
+		 "chain length %d\n", avc_prefix, h->nel, slots_used,
+		 SIDTAB_SIZE, max_chain_len);
+}
+
+void sidtab_destroy(struct sidtab *s)
+{
+	int i;
+	struct sidtab_node *cur, *temp;
+
+	if (!s)
+		return;
+
+	for (i = 0; i < SIDTAB_SIZE; i++) {
+		cur = s->htable[i];
+		while (cur != NULL) {
+			temp = cur;
+			cur = cur->next;
+			freecon(temp->sid_s.ctx);
+			avc_free(temp);
+		}
+		s->htable[i] = NULL;
+	}
+	avc_free(s->htable);
+	s->htable = NULL;
+}
diff --git a/distrib/libselinux/src/avc_sidtab.h b/distrib/libselinux/src/avc_sidtab.h
new file mode 100644
index 0000000..bce9b87
--- /dev/null
+++ b/distrib/libselinux/src/avc_sidtab.h
@@ -0,0 +1,36 @@
+/*
+ * A security identifier table (sidtab) is a hash table
+ * of security context structures indexed by SID value.
+ */
+#ifndef _SELINUX_AVC_SIDTAB_H_
+#define _SELINUX_AVC_SIDTAB_H_
+
+#include <selinux/selinux.h>
+#include <selinux/avc.h>
+#include "dso.h"
+
+struct sidtab_node {
+	struct security_id sid_s;
+	struct sidtab_node *next;
+};
+
+#define SIDTAB_HASH_BITS 7
+#define SIDTAB_HASH_BUCKETS (1 << SIDTAB_HASH_BITS)
+#define SIDTAB_HASH_MASK (SIDTAB_HASH_BUCKETS-1)
+#define SIDTAB_SIZE SIDTAB_HASH_BUCKETS
+
+struct sidtab {
+	struct sidtab_node **htable;
+	unsigned nel;
+};
+
+int sidtab_init(struct sidtab *s) hidden;
+int sidtab_insert(struct sidtab *s, const char * ctx) hidden;
+
+int sidtab_context_to_sid(struct sidtab *s,
+			  const char * ctx, security_id_t * sid) hidden;
+
+void sidtab_sid_stats(struct sidtab *s, char *buf, int buflen) hidden;
+void sidtab_destroy(struct sidtab *s) hidden;
+
+#endif				/* _SELINUX_AVC_SIDTAB_H_ */
diff --git a/distrib/libselinux/src/booleans.c b/distrib/libselinux/src/booleans.c
new file mode 100644
index 0000000..17e0ad8
--- /dev/null
+++ b/distrib/libselinux/src/booleans.c
@@ -0,0 +1,263 @@
+/*
+ * Author: Karl MacMillan <kmacmillan@tresys.com>
+ *
+ * Modified:  
+ *   Dan Walsh <dwalsh@redhat.com> - Added security_load_booleans().
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fnmatch.h>
+#include <limits.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include "selinux_internal.h"
+#include "policy.h"
+
+#define SELINUX_BOOL_DIR "/booleans/"
+
+static int filename_select(const struct dirent *d)
+{
+	if (d->d_name[0] == '.'
+	    && (d->d_name[1] == '\0'
+		|| (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+		return 0;
+	return 1;
+}
+
+int security_get_boolean_names(char ***names, int *len)
+{
+	char path[PATH_MAX];
+	int i, rc;
+	struct dirent **namelist;
+	char **n;
+
+	assert(len);
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s%s", selinux_mnt, SELINUX_BOOL_DIR);
+	*len = scandir(path, &namelist, &filename_select, alphasort);
+	if (*len <= 0) {
+		return -1;
+	}
+
+	n = (char **)malloc(sizeof(char *) * *len);
+	if (!n) {
+		rc = -1;
+		goto bad;
+	}
+
+	for (i = 0; i < *len; i++) {
+	        n[i] = strdup(namelist[i]->d_name);
+		if (!n[i]) {
+			rc = -1;
+			goto bad_freen;
+		}
+	}
+	rc = 0;
+	*names = n;
+      out:
+	for (i = 0; i < *len; i++) {
+		free(namelist[i]);
+	}
+	free(namelist);
+	return rc;
+      bad_freen:
+	for (--i; i >= 0; --i)
+		free(n[i]);
+	free(n);
+      bad:
+	goto out;
+}
+
+hidden_def(security_get_boolean_names)
+#define STRBUF_SIZE 3
+static int get_bool_value(const char *name, char **buf)
+{
+	int fd, len;
+	char *fname = NULL;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	*buf = (char *)malloc(sizeof(char) * (STRBUF_SIZE + 1));
+	if (!*buf)
+		goto out;
+	(*buf)[STRBUF_SIZE] = 0;
+
+	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
+	fname = (char *)malloc(sizeof(char) * len);
+	if (!fname)
+		goto out;
+	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
+
+	fd = open(fname, O_RDONLY);
+	if (fd < 0)
+		goto out;
+
+	len = read(fd, *buf, STRBUF_SIZE);
+	close(fd);
+	if (len != STRBUF_SIZE)
+		goto out;
+
+	free(fname);
+	return 0;
+      out:
+	if (*buf)
+		free(*buf);
+	if (fname)
+		free(fname);
+	return -1;
+}
+
+int security_get_boolean_pending(const char *name)
+{
+	char *buf;
+	int val;
+
+	if (get_bool_value(name, &buf))
+		return -1;
+
+	if (atoi(&buf[1]))
+		val = 1;
+	else
+		val = 0;
+	free(buf);
+	return val;
+}
+
+int security_get_boolean_active(const char *name)
+{
+	char *buf;
+	int val;
+
+	if (get_bool_value(name, &buf))
+		return -1;
+
+	buf[1] = '\0';
+	if (atoi(buf))
+		val = 1;
+	else
+		val = 0;
+	free(buf);
+	return val;
+}
+
+hidden_def(security_get_boolean_active)
+
+int security_set_boolean(const char *name, int value)
+{
+	int fd, ret, len;
+	char buf[2], *fname;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+	if (value < 0 || value > 1) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	len = strlen(name) + strlen(selinux_mnt) + sizeof(SELINUX_BOOL_DIR);
+	fname = (char *)malloc(sizeof(char) * len);
+	if (!fname)
+		return -1;
+	snprintf(fname, len, "%s%s%s", selinux_mnt, SELINUX_BOOL_DIR, name);
+
+	fd = open(fname, O_WRONLY);
+	if (fd < 0) {
+		ret = -1;
+		goto out;
+	}
+
+	if (value)
+		buf[0] = '1';
+	else
+		buf[0] = '0';
+	buf[1] = '\0';
+
+	ret = write(fd, buf, 2);
+	close(fd);
+      out:
+	free(fname);
+	if (ret > 0)
+		return 0;
+	else
+		return -1;
+}
+
+hidden_def(security_set_boolean)
+
+int security_commit_booleans(void)
+{
+	int fd, ret;
+	char buf[2];
+	char path[PATH_MAX];
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/commit_pending_bools", selinux_mnt);
+	fd = open(path, O_WRONLY);
+	if (fd < 0)
+		return -1;
+
+	buf[0] = '1';
+	buf[1] = '\0';
+
+	ret = write(fd, buf, 2);
+	close(fd);
+
+	if (ret > 0)
+		return 0;
+	else
+		return -1;
+}
+
+hidden_def(security_commit_booleans)
+
+static void rollback(SELboolean * boollist, int end)
+{
+	int i;
+
+	for (i = 0; i < end; i++)
+		security_set_boolean(boollist[i].name,
+				     security_get_boolean_active(boollist[i].
+								 name));
+}
+
+int security_set_boolean_list(size_t boolcnt, SELboolean * const boollist,
+			      int permanent __attribute__((unused)))
+{
+
+	size_t i;
+	for (i = 0; i < boolcnt; i++) {
+		if (security_set_boolean(boollist[i].name, boollist[i].value)) {
+			rollback(boollist, i);
+			return -1;
+		}
+	}
+
+	/* OK, let's do the commit */
+	if (security_commit_booleans()) {
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/distrib/libselinux/src/callbacks.c b/distrib/libselinux/src/callbacks.c
new file mode 100644
index 0000000..c3cf98b
--- /dev/null
+++ b/distrib/libselinux/src/callbacks.c
@@ -0,0 +1,124 @@
+/*
+ * User-supplied callbacks and default implementations.
+ * Class and permission mappings.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+#include "callbacks.h"
+
+/* default implementations */
+static int __attribute__ ((format(printf, 2, 3)))
+default_selinux_log(int type __attribute__((unused)), const char *fmt, ...)
+{
+	int rc;
+	va_list ap;
+	va_start(ap, fmt);
+	rc = vfprintf(stderr, fmt, ap);
+	va_end(ap);
+	return rc;
+}
+
+static int
+default_selinux_audit(void *ptr __attribute__((unused)),
+		      security_class_t cls __attribute__((unused)),
+		      char *buf __attribute__((unused)),
+		      size_t len __attribute__((unused)))
+{
+	return 0;
+}
+
+static int
+default_selinux_validate(char **ctx)
+{
+	return security_check_context(*ctx);
+}
+
+static int
+default_selinux_setenforce(int enforcing __attribute__((unused)))
+{
+	return 0;
+}
+
+static int
+default_selinux_policyload(int seqno __attribute__((unused)))
+{
+	return 0;
+}
+
+/* callback pointers */
+int __attribute__ ((format(printf, 2, 3)))
+(*selinux_log)(int, const char *, ...) =
+	default_selinux_log;
+
+int
+(*selinux_audit) (void *, security_class_t, char *, size_t) =
+	default_selinux_audit;
+
+int
+(*selinux_validate)(char **ctx) =
+	default_selinux_validate;
+
+int
+(*selinux_netlink_setenforce) (int enforcing) =
+	default_selinux_setenforce;
+
+int
+(*selinux_netlink_policyload) (int seqno) =
+	default_selinux_policyload;
+
+/* callback setting function */
+void
+selinux_set_callback(int type, union selinux_callback cb)
+{
+	switch (type) {
+	case SELINUX_CB_LOG:
+		selinux_log = cb.func_log;
+		break;
+	case SELINUX_CB_AUDIT:
+		selinux_audit = cb.func_audit;
+		break;
+	case SELINUX_CB_VALIDATE:
+		selinux_validate = cb.func_validate;
+		break;
+	case SELINUX_CB_SETENFORCE:
+		selinux_netlink_setenforce = cb.func_setenforce;
+		break;
+	case SELINUX_CB_POLICYLOAD:
+		selinux_netlink_policyload = cb.func_policyload;
+		break;
+	}
+}
+
+/* callback getting function */
+union selinux_callback
+selinux_get_callback(int type)
+{
+	union selinux_callback cb;
+
+	switch (type) {
+	case SELINUX_CB_LOG:
+		cb.func_log = selinux_log;
+		break;
+	case SELINUX_CB_AUDIT:
+		cb.func_audit = selinux_audit;
+		break;
+	case SELINUX_CB_VALIDATE:
+		cb.func_validate = selinux_validate;
+		break;
+	case SELINUX_CB_SETENFORCE:
+		cb.func_setenforce = selinux_netlink_setenforce;
+		break;
+	case SELINUX_CB_POLICYLOAD:
+		cb.func_policyload = selinux_netlink_policyload;
+		break;
+	default:
+		memset(&cb, 0, sizeof(cb));
+		errno = EINVAL;
+		break;
+	}
+	return cb;
+}
diff --git a/distrib/libselinux/src/callbacks.h b/distrib/libselinux/src/callbacks.h
new file mode 100644
index 0000000..2a572e0
--- /dev/null
+++ b/distrib/libselinux/src/callbacks.h
@@ -0,0 +1,30 @@
+/*
+ * This file describes the callbacks passed to selinux_init() and available
+ * for use from the library code.  They all have default implementations.
+ */
+#ifndef _SELINUX_CALLBACKS_H_
+#define _SELINUX_CALLBACKS_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <selinux/selinux.h>
+#include "dso.h"
+
+/* callback pointers */
+extern int __attribute__ ((format(printf, 2, 3)))
+(*selinux_log) (int type, const char *, ...) hidden;
+
+extern int
+(*selinux_audit) (void *, security_class_t, char *, size_t) hidden;
+
+extern int
+(*selinux_validate)(char **ctx) hidden;
+
+extern int
+(*selinux_netlink_setenforce) (int enforcing) hidden;
+
+extern int
+(*selinux_netlink_policyload) (int seqno) hidden;
+
+#endif				/* _SELINUX_CALLBACKS_H_ */
diff --git a/distrib/libselinux/src/canonicalize_context.c b/distrib/libselinux/src/canonicalize_context.c
new file mode 100644
index 0000000..b8f874f
--- /dev/null
+++ b/distrib/libselinux/src/canonicalize_context.c
@@ -0,0 +1,62 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <limits.h>
+
+int security_canonicalize_context(const char * con,
+				      char ** canoncon)
+{
+	char path[PATH_MAX];
+	char *buf;
+	size_t size;
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/context", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	size = selinux_page_size;
+	buf = malloc(size);
+	if (!buf) {
+		ret = -1;
+		goto out;
+	}
+	strncpy(buf, con, size);
+
+	ret = write(fd, buf, strlen(buf) + 1);
+	if (ret < 0)
+		goto out2;
+
+	memset(buf, 0, size);
+	ret = read(fd, buf, size - 1);
+	if (ret < 0 && errno == EINVAL) {
+		/* Fall back to the original context for kernels
+		   that do not support the extended interface. */
+		strncpy(buf, con, size);
+	}
+
+	*canoncon = strdup(buf);
+	if (!(*canoncon)) {
+		ret = -1;
+		goto out2;
+	}
+	ret = 0;
+      out2:
+	free(buf);
+      out:
+	close(fd);
+	return ret;
+}
+
diff --git a/distrib/libselinux/src/checkAccess.c b/distrib/libselinux/src/checkAccess.c
new file mode 100644
index 0000000..2fb22d9
--- /dev/null
+++ b/distrib/libselinux/src/checkAccess.c
@@ -0,0 +1,41 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "selinux_internal.h"
+#include <selinux/avc.h>
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+static int selinux_enabled;
+
+static void avc_init_once(void)
+{
+	selinux_enabled = is_selinux_enabled();
+	if (selinux_enabled == 1)
+		avc_open(NULL, 0);
+}
+
+int selinux_check_access(const char * scon, const char * tcon, const char *class, const char *perm, void *aux) {
+	int status = -1;
+	int rc = -1;
+	security_id_t scon_id;
+	security_id_t tcon_id;
+	security_class_t sclass;
+	access_vector_t av;
+
+	__selinux_once(once, avc_init_once);
+
+	if (selinux_enabled != 1)
+		return 0;
+
+	if ((rc = avc_context_to_sid(scon, &scon_id)) < 0)  return rc;
+
+	if ((rc = avc_context_to_sid(tcon, &tcon_id)) < 0)  return rc;
+
+	if ((sclass = string_to_security_class(class)) == 0) return status;
+
+	if ((av = string_to_av_perm(sclass, perm)) == 0) return status;
+
+	return avc_has_perm (scon_id, tcon_id, sclass, av, NULL, aux);
+}
+
diff --git a/distrib/libselinux/src/check_context.c b/distrib/libselinux/src/check_context.c
new file mode 100644
index 0000000..7471194
--- /dev/null
+++ b/distrib/libselinux/src/check_context.c
@@ -0,0 +1,33 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <limits.h>
+
+int security_check_context(const char * con)
+{
+	char path[PATH_MAX];
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/context", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	ret = write(fd, con, strlen(con) + 1);
+	close(fd);
+	if (ret < 0)
+		return -1;
+	return 0;
+}
+
diff --git a/distrib/libselinux/src/compute_av.c b/distrib/libselinux/src/compute_av.c
new file mode 100644
index 0000000..d6f76f8
--- /dev/null
+++ b/distrib/libselinux/src/compute_av.c
@@ -0,0 +1,72 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include "mapping.h"
+
+int security_compute_av(const char * scon,
+			const char * tcon,
+			security_class_t tclass,
+			access_vector_t requested,
+			struct av_decision *avd)
+{
+	char path[PATH_MAX];
+	char *buf;
+	size_t len;
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/access", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	len = selinux_page_size;
+	buf = malloc(len);
+	if (!buf) {
+		ret = -1;
+		goto out;
+	}
+
+	snprintf(buf, len, "%s %s %hu %x", scon, tcon,
+		 unmap_class(tclass), unmap_perm(tclass, requested));
+
+	ret = write(fd, buf, strlen(buf));
+	if (ret < 0)
+		goto out2;
+
+	memset(buf, 0, len);
+	ret = read(fd, buf, len - 1);
+	if (ret < 0)
+		goto out2;
+
+	ret = sscanf(buf, "%x %x %x %x %u %x",
+		     &avd->allowed, &avd->decided,
+		     &avd->auditallow, &avd->auditdeny,
+		     &avd->seqno, &avd->flags);
+	if (ret < 5) {
+		ret = -1;
+		goto out2;
+	} else if (ret < 6)
+		avd->flags = 0;
+
+	map_decision(tclass, avd);
+
+	ret = 0;
+      out2:
+	free(buf);
+      out:
+	close(fd);
+	return ret;
+}
+
diff --git a/distrib/libselinux/src/compute_create.c b/distrib/libselinux/src/compute_create.c
new file mode 100644
index 0000000..d3b16c9
--- /dev/null
+++ b/distrib/libselinux/src/compute_create.c
@@ -0,0 +1,61 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include "mapping.h"
+
+int security_compute_create(const char * scon,
+				const char * tcon,
+				security_class_t tclass,
+				char ** newcon)
+{
+	char path[PATH_MAX];
+	char *buf;
+	size_t size;
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/create", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	size = selinux_page_size;
+	buf = malloc(size);
+	if (!buf) {
+		ret = -1;
+		goto out;
+	}
+	snprintf(buf, size, "%s %s %hu", scon, tcon, unmap_class(tclass));
+
+	ret = write(fd, buf, strlen(buf));
+	if (ret < 0)
+		goto out2;
+
+	memset(buf, 0, size);
+	ret = read(fd, buf, size - 1);
+	if (ret < 0)
+		goto out2;
+
+	*newcon = strdup(buf);
+	if (!(*newcon)) {
+		ret = -1;
+		goto out2;
+	}
+	ret = 0;
+      out2:
+	free(buf);
+      out:
+	close(fd);
+	return ret;
+}
diff --git a/distrib/libselinux/src/context.c b/distrib/libselinux/src/context.c
new file mode 100644
index 0000000..66abea1
--- /dev/null
+++ b/distrib/libselinux/src/context.c
@@ -0,0 +1,197 @@
+#include "context_internal.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#define COMP_USER  0
+#define COMP_ROLE  1
+#define COMP_TYPE  2
+#define COMP_RANGE 3
+
+typedef struct {
+	char *current_str;	/* This is made up-to-date only when needed */
+	char *(component[4]);
+} context_private_t;
+
+/*
+ * Allocate a new context, initialized from str.  There must be 3 or
+ * 4 colon-separated components and no whitespace in any component other
+ * than the MLS component.
+ */
+context_t context_new(const char *str)
+{
+	int i, count;
+	errno = 0;
+	context_private_t *n =
+	    (context_private_t *) malloc(sizeof(context_private_t));
+	context_t result = (context_t) malloc(sizeof(context_s_t));
+	const char *p, *tok;
+
+	if (result)
+		result->ptr = n;
+	else
+		free(n);
+	if (n == 0 || result == 0) {
+		goto err;
+	}
+	n->current_str = n->component[0] = n->component[1] = n->component[2] =
+	    n->component[3] = 0;
+	for (i = count = 0, p = str; *p; p++) {
+		switch (*p) {
+		case ':':
+			count++;
+			break;
+		case '\n':
+		case '\t':
+		case '\r':
+			goto err;	/* sanity check */
+		case ' ':
+			if (count < 3)
+				goto err;	/* sanity check */
+		}
+	}
+	/*
+	 * Could be anywhere from 2 - 5
+	 * e.g user:role:type to user:role:type:sens1:cata-sens2:catb
+	 */
+	if (count < 2 || count > 5) {	/* might not have a range */
+		goto err;
+	}
+
+	n->component[3] = 0;
+	for (i = 0, tok = str; *tok; i++) {
+		if (i < 3)
+			for (p = tok; *p && *p != ':'; p++) {	/* empty */
+		} else {
+			/* MLS range is one component */
+			for (p = tok; *p; p++) {	/* empty */
+			}
+		}
+		n->component[i] = (char *)malloc(p - tok + 1);
+		if (n->component[i] == 0)
+			goto err;
+		strncpy(n->component[i], tok, p - tok);
+		n->component[i][p - tok] = '\0';
+		tok = *p ? p + 1 : p;
+	}
+	return result;
+      err:
+	if (errno == 0) errno = EINVAL;
+	context_free(result);
+	return 0;
+}
+
+hidden_def(context_new)
+
+static void conditional_free(char **v)
+{
+	if (*v) {
+		free(*v);
+	}
+	*v = 0;
+}
+
+/*
+ * free all storage used by a context.  Safe to call with
+ * null pointer. 
+ */
+void context_free(context_t context)
+{
+	context_private_t *n;
+	int i;
+	if (context) {
+		n = context->ptr;
+		if (n) {
+			conditional_free(&n->current_str);
+			for (i = 0; i < 4; i++) {
+				conditional_free(&n->component[i]);
+			}
+			free(n);
+		}
+		free(context);
+	}
+}
+
+hidden_def(context_free)
+
+/*
+ * Return a pointer to the string value of the context.
+ */
+char *context_str(context_t context)
+{
+	context_private_t *n = context->ptr;
+	int i;
+	size_t total = 0;
+	conditional_free(&n->current_str);
+	for (i = 0; i < 4; i++) {
+		if (n->component[i]) {
+			total += strlen(n->component[i]) + 1;
+		}
+	}
+	n->current_str = malloc(total);
+	if (n->current_str != 0) {
+		char *cp = n->current_str;
+
+		strcpy(cp, n->component[0]);
+		cp += strlen(cp);
+		for (i = 1; i < 4; i++) {
+			if (n->component[i]) {
+				*cp++ = ':';
+				strcpy(cp, n->component[i]);
+				cp += strlen(cp);
+			}
+		}
+	}
+	return n->current_str;
+}
+
+hidden_def(context_str)
+
+/* Returns nonzero iff failed */
+static int set_comp(context_private_t * n, int idx, const char *str)
+{
+	char *t = NULL;
+	const char *p;
+	if (str) {
+		t = (char *)malloc(strlen(str) + 1);
+		if (!t) {
+			return 1;
+		}
+		for (p = str; *p; p++) {
+			if (*p == '\t' || *p == '\n' || *p == '\r' ||
+			    ((*p == ':' || *p == ' ') && idx != COMP_RANGE)) {
+				free(t);
+				errno = EINVAL;
+				return 1;
+			}
+		}
+		strcpy(t, str);
+	}
+	conditional_free(&n->component[idx]);
+	n->component[idx] = t;
+	return 0;
+}
+
+#define def_get(name,tag) \
+const char * context_ ## name ## _get(context_t context) \
+{ \
+        context_private_t *n = context->ptr; \
+        return n->component[tag]; \
+} \
+hidden_def(context_ ## name ## _get)
+
+def_get(type, COMP_TYPE)
+    def_get(user, COMP_USER)
+    def_get(range, COMP_RANGE)
+    def_get(role, COMP_ROLE)
+#define def_set(name,tag) \
+int context_ ## name ## _set(context_t context, const char* str) \
+{ \
+        return set_comp(context->ptr,tag,str);\
+} \
+hidden_def(context_ ## name ## _set)
+    def_set(type, COMP_TYPE)
+    def_set(role, COMP_ROLE)
+    def_set(user, COMP_USER)
+    def_set(range, COMP_RANGE)
diff --git a/distrib/libselinux/src/context_internal.h b/distrib/libselinux/src/context_internal.h
new file mode 100644
index 0000000..3c71e80
--- /dev/null
+++ b/distrib/libselinux/src/context_internal.h
@@ -0,0 +1,14 @@
+#include <selinux/context.h>
+#include "dso.h"
+
+hidden_proto(context_new)
+    hidden_proto(context_free)
+    hidden_proto(context_str)
+    hidden_proto(context_type_set)
+    hidden_proto(context_type_get)
+    hidden_proto(context_role_set)
+    hidden_proto(context_role_get)
+    hidden_proto(context_user_set)
+    hidden_proto(context_user_get)
+    hidden_proto(context_range_set)
+    hidden_proto(context_range_get)
diff --git a/distrib/libselinux/src/deny_unknown.c b/distrib/libselinux/src/deny_unknown.c
new file mode 100644
index 0000000..c93998a
--- /dev/null
+++ b/distrib/libselinux/src/deny_unknown.c
@@ -0,0 +1,40 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <stdio.h>
+#include <limits.h>
+
+int security_deny_unknown(void)
+{
+	int fd, ret, deny_unknown = 0;
+	char path[PATH_MAX];
+	char buf[20];
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof(path), "%s/deny_unknown", selinux_mnt);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	memset(buf, 0, sizeof(buf));
+	ret = read(fd, buf, sizeof(buf) - 1);
+	close(fd);
+	if (ret < 0)
+		return -1;
+
+	if (sscanf(buf, "%d", &deny_unknown) != 1)
+		return -1;
+
+	return deny_unknown;
+}
+
+hidden_def(security_deny_unknown);
diff --git a/distrib/libselinux/src/disable.c b/distrib/libselinux/src/disable.c
new file mode 100644
index 0000000..dac0f5b
--- /dev/null
+++ b/distrib/libselinux/src/disable.c
@@ -0,0 +1,38 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <stdio.h>
+#include <limits.h>
+
+int security_disable(void)
+{
+	int fd, ret;
+	char path[PATH_MAX];
+	char buf[20];
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/disable", selinux_mnt);
+	fd = open(path, O_WRONLY);
+	if (fd < 0)
+		return -1;
+
+	buf[0] = '1';
+	buf[1] = '\0';
+	ret = write(fd, buf, strlen(buf));
+	close(fd);
+	if (ret < 0)
+		return -1;
+
+	return 0;
+}
+
+hidden_def(security_disable)
diff --git a/distrib/libselinux/src/dso.h b/distrib/libselinux/src/dso.h
new file mode 100644
index 0000000..12c3d11
--- /dev/null
+++ b/distrib/libselinux/src/dso.h
@@ -0,0 +1,23 @@
+#ifndef _SELINUX_DSO_H
+#define _SELINUX_DSO_H	1
+
+#ifdef SHARED
+# define hidden __attribute__ ((visibility ("hidden")))
+# define hidden_proto(fct) __hidden_proto (fct, fct##_internal)
+# define __hidden_proto(fct, internal)	\
+     extern __typeof (fct) internal;	\
+     extern __typeof (fct) fct __asm (#internal) hidden;
+# if defined(__alpha__) || defined(__mips__)
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n" #fct " = " #fct "_internal");
+# else
+#  define hidden_def(fct) \
+     asm (".globl " #fct "\n.set " #fct ", " #fct "_internal");
+#endif
+#else
+# define hidden
+# define hidden_proto(fct)
+# define hidden_def(fct)
+#endif
+
+#endif
diff --git a/distrib/libselinux/src/enabled.c b/distrib/libselinux/src/enabled.c
new file mode 100644
index 0000000..ab015a4
--- /dev/null
+++ b/distrib/libselinux/src/enabled.c
@@ -0,0 +1,100 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include "policy.h"
+
+int is_selinux_enabled(void)
+{
+	char buf[BUFSIZ];
+	FILE *fp;
+	char *bufp;
+	int enabled = 0;
+	char * con;
+
+	/* init_selinuxmnt() gets called before this function. We
+ 	 * will assume that if a selinux file system is mounted, then
+ 	 * selinux is enabled. */
+	if (selinux_mnt) {
+
+		/* Since a file system is mounted, we consider selinux
+		 * enabled. If getcon fails, selinux is still enabled.
+		 * We only consider it disabled if no policy is loaded. */
+		enabled = 1;
+		if (getcon(&con) == 0) {
+			if (!strcmp(con, "kernel"))
+				enabled = 0;
+			freecon(con);
+		}
+		return enabled;
+        }
+
+	/* Drop back to detecting it the long way. */
+	fp = fopen("/proc/filesystems", "r");
+	if (!fp)
+		return -1;
+
+	while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) {
+		if (strstr(buf, "selinuxfs")) {
+			enabled = 1;
+			break;
+		}
+	}
+
+	if (!bufp)
+		goto out;
+
+	/* Since an selinux file system is available, we consider
+	 * selinux enabled. If getcon fails, selinux is still
+	 * enabled. We only consider it disabled if no policy is loaded. */
+	if (getcon(&con) == 0) {
+		if (!strcmp(con, "kernel"))
+			enabled = 0;
+		freecon(con);
+	}
+
+      out:
+	fclose(fp);
+	return enabled;
+}
+
+hidden_def(is_selinux_enabled)
+
+/*
+ * Function: is_selinux_mls_enabled()
+ * Return:   1 on success
+ *	     0 on failure
+ */
+int is_selinux_mls_enabled(void)
+{
+	char buf[20], path[PATH_MAX];
+	int fd, ret, enabled = 0;
+
+	if (!selinux_mnt)
+		return enabled;
+
+	snprintf(path, sizeof path, "%s/mls", selinux_mnt);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return enabled;
+
+	memset(buf, 0, sizeof buf);
+
+	do {
+		ret = read(fd, buf, sizeof buf - 1);
+	} while (ret < 0 && errno == EINTR);
+	close(fd);
+	if (ret < 0)
+		return enabled;
+
+	if (!strcmp(buf, "1"))
+		enabled = 1;
+
+	return enabled;
+}
+
+hidden_def(is_selinux_mls_enabled)
diff --git a/distrib/libselinux/src/fgetfilecon.c b/distrib/libselinux/src/fgetfilecon.c
new file mode 100644
index 0000000..33cdc27
--- /dev/null
+++ b/distrib/libselinux/src/fgetfilecon.c
@@ -0,0 +1,51 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+int fgetfilecon(int fd, char ** context)
+{
+	char *buf;
+	ssize_t size;
+	ssize_t ret;
+
+	size = INITCONTEXTLEN + 1;
+	buf = malloc(size);
+	if (!buf)
+		return -1;
+	memset(buf, 0, size);
+
+	ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
+	if (ret < 0 && errno == ERANGE) {
+		char *newbuf;
+
+		size = fgetxattr(fd, XATTR_NAME_SELINUX, NULL, 0);
+		if (size < 0)
+			goto out;
+
+		size++;
+		newbuf = realloc(buf, size);
+		if (!newbuf)
+			goto out;
+
+		buf = newbuf;
+		memset(buf, 0, size);
+		ret = fgetxattr(fd, XATTR_NAME_SELINUX, buf, size - 1);
+	}
+      out:
+	if (ret == 0) {
+		/* Re-map empty attribute values to errors. */
+		errno = EOPNOTSUPP;
+		ret = -1;
+	}
+	if (ret < 0)
+		free(buf);
+	else
+		*context = buf;
+	return ret;
+}
+
diff --git a/distrib/libselinux/src/freecon.c b/distrib/libselinux/src/freecon.c
new file mode 100644
index 0000000..5290dfa
--- /dev/null
+++ b/distrib/libselinux/src/freecon.c
@@ -0,0 +1,11 @@
+#include <unistd.h>
+#include "selinux_internal.h"
+#include <stdlib.h>
+#include <errno.h>
+
+void freecon(char * con)
+{
+	free(con);
+}
+
+hidden_def(freecon)
diff --git a/distrib/libselinux/src/fsetfilecon.c b/distrib/libselinux/src/fsetfilecon.c
new file mode 100644
index 0000000..17f8875
--- /dev/null
+++ b/distrib/libselinux/src/fsetfilecon.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+int fsetfilecon(int fd, const char *context)
+{
+	return fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1,
+			 0);
+}
+
diff --git a/distrib/libselinux/src/get_initial_context.c b/distrib/libselinux/src/get_initial_context.c
new file mode 100644
index 0000000..64863dd
--- /dev/null
+++ b/distrib/libselinux/src/get_initial_context.c
@@ -0,0 +1,55 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <limits.h>
+
+#define SELINUX_INITCON_DIR "/initial_contexts/"
+
+int security_get_initial_context(const char * name, char ** con)
+{
+	char path[PATH_MAX];
+	char *buf;
+	size_t size;
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s%s%s", 
+		 selinux_mnt, SELINUX_INITCON_DIR, name);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	size = selinux_page_size;
+	buf = malloc(size);
+	if (!buf) {
+		ret = -1;
+		goto out;
+	}
+	memset(buf, 0, size);
+	ret = read(fd, buf, size - 1);
+	if (ret < 0)
+		goto out2;
+
+	*con = strdup(buf);
+	if (!(*con)) {
+		ret = -1;
+		goto out2;
+	}
+	ret = 0;
+      out2:
+	free(buf);
+      out:
+	close(fd);
+	return ret;
+}
+
diff --git a/distrib/libselinux/src/getenforce.c b/distrib/libselinux/src/getenforce.c
new file mode 100644
index 0000000..4fb516a
--- /dev/null
+++ b/distrib/libselinux/src/getenforce.c
@@ -0,0 +1,40 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <stdio.h>
+#include <limits.h>
+
+int security_getenforce(void)
+{
+	int fd, ret, enforce = 0;
+	char path[PATH_MAX];
+	char buf[20];
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -1;
+
+	memset(buf, 0, sizeof buf);
+	ret = read(fd, buf, sizeof buf - 1);
+	close(fd);
+	if (ret < 0)
+		return -1;
+
+	if (sscanf(buf, "%d", &enforce) != 1)
+		return -1;
+
+	return enforce;
+}
+
+hidden_def(security_getenforce)
diff --git a/distrib/libselinux/src/getfilecon.c b/distrib/libselinux/src/getfilecon.c
new file mode 100644
index 0000000..02037de
--- /dev/null
+++ b/distrib/libselinux/src/getfilecon.c
@@ -0,0 +1,50 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "policy.h"
+
+int getfilecon(const char *path, char ** context)
+{
+	char *buf;
+	ssize_t size;
+	ssize_t ret;
+
+	size = INITCONTEXTLEN + 1;
+	buf = malloc(size);
+	if (!buf)
+		return -1;
+	memset(buf, 0, size);
+
+	ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
+	if (ret < 0 && errno == ERANGE) {
+		char *newbuf;
+
+		size = getxattr(path, XATTR_NAME_SELINUX, NULL, 0);
+		if (size < 0)
+			goto out;
+
+		size++;
+		newbuf = realloc(buf, size);
+		if (!newbuf)
+			goto out;
+
+		buf = newbuf;
+		memset(buf, 0, size);
+		ret = getxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
+	}
+      out:
+	if (ret == 0) {
+		/* Re-map empty attribute values to errors. */
+		errno = EOPNOTSUPP;
+		ret = -1;
+	}
+	if (ret < 0)
+		free(buf);
+	else
+		*context = buf;
+	return ret;
+}
diff --git a/distrib/libselinux/src/getpeercon.c b/distrib/libselinux/src/getpeercon.c
new file mode 100644
index 0000000..3bd29dc
--- /dev/null
+++ b/distrib/libselinux/src/getpeercon.c
@@ -0,0 +1,45 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+#ifndef SO_PEERSEC
+#define SO_PEERSEC 31
+#endif
+
+int getpeercon(int fd, char ** context)
+{
+	char *buf;
+	socklen_t size;
+	ssize_t ret;
+
+	size = INITCONTEXTLEN + 1;
+	buf = malloc(size);
+	if (!buf)
+		return -1;
+	memset(buf, 0, size);
+
+	ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size);
+	if (ret < 0 && errno == ERANGE) {
+		char *newbuf;
+
+		newbuf = realloc(buf, size);
+		if (!newbuf)
+			goto out;
+
+		buf = newbuf;
+		memset(buf, 0, size);
+		ret = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buf, &size);
+	}
+      out:
+	if (ret < 0)
+		free(buf);
+	else
+		*context = buf;
+	return ret;
+}
+
diff --git a/distrib/libselinux/src/init.c b/distrib/libselinux/src/init.c
new file mode 100644
index 0000000..65bc01b
--- /dev/null
+++ b/distrib/libselinux/src/init.c
@@ -0,0 +1,123 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+#ifdef DARWIN
+#include <sys/param.h>
+#include <sys/mount.h>
+#else
+#include <sys/vfs.h>
+#endif
+
+#include <stdint.h>
+#include <limits.h>
+
+#include "dso.h"
+#include "policy.h"
+#include "selinux_internal.h"
+
+char *selinux_mnt = NULL;
+int selinux_page_size = 0;
+
+static void init_selinuxmnt(void)
+{
+	char buf[BUFSIZ], *p;
+	FILE *fp=NULL;
+	struct statfs sfbuf;
+	int rc;
+	char *bufp;
+	int exists = 0;
+
+	if (selinux_mnt)
+		return;
+
+	/* We check to see if the preferred mount point for selinux file
+	 * system has a selinuxfs. */
+	do {
+		rc = statfs(SELINUXMNT, &sfbuf);
+	} while (rc < 0 && errno == EINTR);
+	if (rc == 0) {
+		if ((uint32_t)sfbuf.f_type == (uint32_t)SELINUX_MAGIC) {
+			selinux_mnt = strdup(SELINUXMNT);
+			return;
+		}
+	} 
+
+	/* Drop back to detecting it the long way. */
+	fp = fopen("/proc/filesystems", "r");
+	if (!fp)
+		return;
+
+	while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) {
+		if (strstr(buf, "selinuxfs")) {
+			exists = 1;
+			break;
+		}
+	}
+
+	if (!exists) 
+		goto out;
+
+	fclose(fp);
+
+	/* At this point, the usual spot doesn't have an selinuxfs so
+	 * we look around for it */
+	fp = fopen("/proc/mounts", "r");
+	if (!fp)
+		goto out;
+
+	while ((bufp = fgets(buf, sizeof buf - 1, fp)) != NULL) {
+		char *tmp;
+		p = strchr(buf, ' ');
+		if (!p)
+			goto out;
+		p++;
+		tmp = strchr(p, ' ');
+		if (!tmp)
+			goto out;
+		if (!strncmp(tmp + 1, "selinuxfs ", 10)) {
+			*tmp = '\0';
+			break;
+		}
+	}
+
+	/* If we found something, dup it */
+	if (bufp)
+		selinux_mnt = strdup(p);
+
+      out:
+	if (fp)
+		fclose(fp);
+	return;
+}
+
+void fini_selinuxmnt(void)
+{
+	free(selinux_mnt);
+	selinux_mnt = NULL;
+}
+
+void set_selinuxmnt(const char *mnt)
+{
+	selinux_mnt = strdup(mnt);
+}
+
+hidden_def(set_selinuxmnt)
+
+static void init_lib(void) __attribute__ ((constructor));
+static void init_lib(void)
+{
+	selinux_page_size = sysconf(_SC_PAGE_SIZE);
+	init_selinuxmnt();
+}
+
+static void fini_lib(void) __attribute__ ((destructor));
+static void fini_lib(void)
+{
+	fini_selinuxmnt();
+}
diff --git a/distrib/libselinux/src/label.c b/distrib/libselinux/src/label.c
new file mode 100644
index 0000000..800a8a2
--- /dev/null
+++ b/distrib/libselinux/src/label.c
@@ -0,0 +1,143 @@
+/*
+ * Generalized labeling frontend for userspace object managers.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <selinux/selinux.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+typedef int (*selabel_initfunc)(struct selabel_handle *rec,
+				const struct selinux_opt *opts,
+				unsigned nopts);
+
+static selabel_initfunc initfuncs[] = {
+	&selabel_file_init,
+	NULL,
+	NULL,
+	NULL,
+	&selabel_property_init,
+};
+
+/*
+ * Validation functions
+ */
+
+static inline int selabel_is_validate_set(const struct selinux_opt *opts,
+					  unsigned n)
+{
+	while (n--)
+		if (opts[n].type == SELABEL_OPT_VALIDATE)
+			return !!opts[n].value;
+
+	return 0;
+}
+
+int selabel_validate(struct selabel_handle *rec,
+		     struct selabel_lookup_rec *contexts)
+{
+	int rc = 0;
+
+	if (!rec->validating || contexts->validated)
+		goto out;
+
+	rc = selinux_validate(&contexts->ctx_raw);
+	if (rc < 0)
+		goto out;
+
+	contexts->validated = 1;
+out:
+	return rc;
+}
+
+/*
+ * Public API
+ */
+
+struct selabel_handle *selabel_open(unsigned int backend,
+				    const struct selinux_opt *opts,
+				    unsigned nopts)
+{
+	struct selabel_handle *rec = NULL;
+
+	if (backend >= ARRAY_SIZE(initfuncs)) {
+		errno = EINVAL;
+		goto out;
+	}
+
+	if (initfuncs[backend] == NULL)
+		goto out;
+
+	rec = (struct selabel_handle *)malloc(sizeof(*rec));
+	if (!rec)
+		goto out;
+
+	memset(rec, 0, sizeof(*rec));
+	rec->backend = backend;
+	rec->validating = selabel_is_validate_set(opts, nopts);
+
+	if ((*initfuncs[backend])(rec, opts, nopts)) {
+		free(rec);
+		rec = NULL;
+	}
+
+out:
+	return rec;
+}
+
+static struct selabel_lookup_rec *
+selabel_lookup_common(struct selabel_handle *rec,
+		      const char *key, int type)
+{
+	struct selabel_lookup_rec *lr;
+	lr = rec->func_lookup(rec, key, type); 
+	if (!lr)
+		return NULL;
+
+	return lr;
+}
+
+int selabel_lookup(struct selabel_handle *rec, char **con,
+		   const char *key, int type)
+{
+	struct selabel_lookup_rec *lr;
+
+	lr = selabel_lookup_common(rec, key, type);
+	if (!lr)
+		return -1;
+
+	*con = strdup(lr->ctx_raw);
+	return *con ? 0 : -1;
+}
+
+bool selabel_partial_match(struct selabel_handle *rec, const char *key)
+{
+	if (!rec->func_partial_match) {
+		/*
+		 * If the label backend does not support partial matching,
+		 * then assume a match is possible.
+		 */
+		return true;
+	}
+	return rec->func_partial_match(rec, key);
+}
+
+void selabel_close(struct selabel_handle *rec)
+{
+	rec->func_close(rec);
+	free(rec);
+}
+
+void selabel_stats(struct selabel_handle *rec)
+{
+	rec->func_stats(rec);
+}
diff --git a/distrib/libselinux/src/label_android_property.c b/distrib/libselinux/src/label_android_property.c
new file mode 100644
index 0000000..934937d
--- /dev/null
+++ b/distrib/libselinux/src/label_android_property.c
@@ -0,0 +1,301 @@
+/*
+ * Property Service contexts backend for labeling Android 
+ * property keys
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/* A property security context specification. */
+typedef struct spec {
+	struct selabel_lookup_rec lr;	 /* holds contexts for lookup result */
+	char *property_key;	         /* property key string */
+} spec_t;
+
+/* Our stored configuration */
+struct saved_data {
+	/*
+	 * The array of specifications is sorted for longest
+	 * prefix match
+	 */
+	spec_t *spec_arr;
+	unsigned int nspec; /* total number of specifications */
+};
+
+static int cmp(const void *A, const void *B)
+{
+	const struct spec *sp1 = A, *sp2 = B;
+
+	if (strncmp(sp1->property_key,"*",1) == 0)
+		return 1;
+	if (strncmp(sp2->property_key,"*",1) == 0)
+		return -1;
+
+	size_t L1 = strlen(sp1->property_key);
+	size_t L2 = strlen(sp2->property_key);
+
+	return (L1 < L2) - (L1 > L2);
+}
+
+/*
+ * Warn about duplicate specifications.
+ */
+static int nodups_specs(struct saved_data *data, const char *path)
+{
+	int rc = 0;
+	unsigned int ii, jj;
+	struct spec *curr_spec, *spec_arr = data->spec_arr;
+
+	for (ii = 0; ii < data->nspec; ii++) {
+		curr_spec = &spec_arr[ii];
+		for (jj = ii + 1; jj < data->nspec; jj++) {
+			if ((!strcmp(spec_arr[jj].property_key, curr_spec->property_key))) {
+				rc = -1;
+				errno = EINVAL;
+				if (strcmp
+				    (spec_arr[jj].lr.ctx_raw,
+				     curr_spec->lr.ctx_raw)) {
+					selinux_log
+						(SELINUX_ERROR,
+						 "%s: Multiple different specifications for %s  (%s and %s).\n",
+						 path, curr_spec->property_key,
+						 spec_arr[jj].lr.ctx_raw,
+						 curr_spec->lr.ctx_raw);
+				} else {
+					selinux_log
+						(SELINUX_ERROR,
+						 "%s: Multiple same specifications for %s.\n",
+						 path, curr_spec->property_key);
+				}
+			}
+		}
+	}
+	return rc;
+}
+
+static int process_line(struct selabel_handle *rec,
+			const char *path, char *line_buf, 
+			int pass, unsigned lineno)
+{
+	int items, len;
+	char buf1[BUFSIZ], buf2[BUFSIZ];
+	char *buf_p, *prop = buf1, *context = buf2;
+	struct saved_data *data = (struct saved_data *)rec->data;
+	spec_t *spec_arr = data->spec_arr;
+	unsigned int nspec = data->nspec;
+
+	len = strlen(line_buf);
+	if (line_buf[len - 1] == '\n')
+		line_buf[len - 1] = 0;
+	buf_p = line_buf;
+	while (isspace(*buf_p))
+		buf_p++;
+	/* Skip comment lines and empty lines. */
+	if (*buf_p == '#' || *buf_p == 0)
+		return 0;
+	items = sscanf(line_buf, "%255s %255s", prop, context);
+	if (items != 2) {
+		selinux_log(SELINUX_WARNING,
+			    "%s:  line %d is missing fields, skipping\n", path,
+			    lineno);
+		return 0;
+	}
+
+	if (pass == 1) {
+		/* On the second pass, process and store the specification in spec. */
+		spec_arr[nspec].property_key = strdup(prop);
+		if (!spec_arr[nspec].property_key) {
+			selinux_log(SELINUX_WARNING,
+				    "%s:  out of memory at line %d on prop %s\n",
+				    path, lineno, prop);
+		return -1;
+	    
+		}
+
+		spec_arr[nspec].lr.ctx_raw = strdup(context);
+		if (!spec_arr[nspec].lr.ctx_raw) {
+			selinux_log(SELINUX_WARNING,
+				    "%s:  out of memory at line %d on context %s\n",
+				    path, lineno, context);
+		return -1;
+		}
+
+		if (rec->validating) {
+		        if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
+			        selinux_log(SELINUX_WARNING,
+					    "%s:  line %d has invalid context %s\n",
+					    path, lineno, spec_arr[nspec].lr.ctx_raw);
+			}
+		}
+     	}
+
+	data->nspec = ++nspec;
+	return 0;
+}
+
+static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		unsigned n)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	const char *path = NULL;
+	FILE *fp;
+	char line_buf[BUFSIZ];
+	unsigned int lineno = 0, maxnspec, pass;
+	int status = -1;
+	struct stat sb;
+
+	/* Process arguments */
+	while (n--)
+		switch (opts[n].type) {
+		case SELABEL_OPT_PATH:
+			path = opts[n].value;
+			break;
+		}
+
+	/* Open the specification file. */
+	if ((fp = fopen(path, "r")) == NULL)
+		return -1;
+
+	if (fstat(fileno(fp), &sb) < 0)
+		return -1;
+	if (!S_ISREG(sb.st_mode)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * Two passes of the specification file. First is to get the size.
+	 * After the first pass, the spec array is malloced to the appropriate 
+	 * size. Second pass is to populate the spec array and check for 
+	 * dups.
+	 */
+	maxnspec = UINT_MAX / sizeof(spec_t);
+	for (pass = 0; pass < 2; pass++) {
+		data->nspec = 0;
+
+		while (fgets(line_buf, sizeof line_buf - 1, fp)
+		       && data->nspec < maxnspec) {
+			if (process_line(rec, path, line_buf, pass, ++lineno) != 0) {
+				goto finish;
+			}
+		}
+
+		if (pass == 1) {
+			status = nodups_specs(data, path);
+	    
+			if (status)
+				goto finish;
+		}
+
+		if (pass == 0) {
+
+			if (data->nspec == 0) {
+				status = 0;
+				goto finish;
+			}
+
+			if (NULL == (data->spec_arr =
+				     malloc(sizeof(spec_t) * data->nspec)))
+				goto finish;
+
+			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+			maxnspec = data->nspec;
+			rewind(fp);
+		}
+	}
+
+	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
+
+	status = 0;
+finish:
+	fclose(fp);
+	return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void closef(struct selabel_handle *rec)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	struct spec *spec;
+	unsigned int i;
+
+	for (i = 0; i < data->nspec; i++) {
+		spec = &data->spec_arr[i];
+		free(spec->property_key);
+		free(spec->lr.ctx_raw);
+		free(spec->lr.ctx_trans);
+	}
+
+	if (data->spec_arr)
+		free(data->spec_arr);
+	
+	free(data);
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 
+					 const char *key, 
+					 int __attribute__((unused)) type)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	spec_t *spec_arr = data->spec_arr;
+	unsigned int i;
+	struct selabel_lookup_rec *ret = NULL;
+
+	if (!data->nspec) {
+		errno = ENOENT;
+		goto finish;
+	}
+
+	for (i = 0; i < data->nspec; i++) {
+		if (strncmp(spec_arr[i].property_key, key, 
+		    strlen(spec_arr[i].property_key)) == 0) {
+			break;
+		}
+		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
+			break;
+	}
+
+	if (i >= data->nspec) {
+		/* No matching specification. */
+		errno = ENOENT;
+		goto finish;
+	}
+
+	ret = &spec_arr[i].lr;
+
+finish:
+	return ret;
+}
+
+static void stats(struct selabel_handle __attribute__((unused)) *rec)
+{
+	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
+}
+
+int selabel_property_init(struct selabel_handle *rec,
+			  const struct selinux_opt *opts,
+			  unsigned nopts)
+{
+	struct saved_data *data;
+
+	data = (struct saved_data *)malloc(sizeof(*data));
+	if (!data)
+		return -1;
+	memset(data, 0, sizeof(*data));
+
+	rec->data = data;
+	rec->func_close = &closef;
+	rec->func_stats = &stats;
+	rec->func_lookup = &lookup;
+
+	return init(rec, opts, nopts);
+}
diff --git a/distrib/libselinux/src/label_file.c b/distrib/libselinux/src/label_file.c
new file mode 100644
index 0000000..9923e38
--- /dev/null
+++ b/distrib/libselinux/src/label_file.c
@@ -0,0 +1,731 @@
+/*
+ * File contexts backend for labeling system
+ *
+ * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
+ */
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <regex.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "callbacks.h"
+#include "label_internal.h"
+
+/*
+ * Internals, mostly moved over from matchpathcon.c
+ */
+
+/* A file security context specification. */
+typedef struct spec {
+	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
+	char *regex_str;	/* regular expession string for diagnostics */
+	char *type_str;		/* type string for diagnostic messages */
+	regex_t regex;		/* compiled regular expression */
+	char regcomp;           /* regex_str has been compiled to regex */
+	mode_t mode;		/* mode format value */
+	int matches;		/* number of matching pathnames */
+	int hasMetaChars;	/* regular expression has meta-chars */
+	int stem_id;		/* indicates which stem-compression item */
+	size_t prefix_len;      /* length of fixed path prefix */
+} spec_t;
+
+/* A regular expression stem */
+typedef struct stem {
+	char *buf;
+	int len;
+} stem_t;
+
+/* Our stored configuration */
+struct saved_data {
+	/*
+	 * The array of specifications, initially in the same order as in 
+	 * the specification file. Sorting occurs based on hasMetaChars.
+	 */
+	spec_t *spec_arr;
+	unsigned int nspec;
+	unsigned int ncomp;
+
+	/*
+	 * The array of regular expression stems.
+	 */
+	stem_t *stem_arr;
+	int num_stems;
+	int alloc_stems;
+};
+
+/* Return the length of the text that can be considered the stem, returns 0
+ * if there is no identifiable stem */
+static int get_stem_from_spec(const char *const buf)
+{
+	const char *tmp = strchr(buf + 1, '/');
+	const char *ind;
+
+	if (!tmp)
+		return 0;
+
+	for (ind = buf; ind < tmp; ind++) {
+		if (strchr(".^$?*+|[({", (int)*ind))
+			return 0;
+	}
+	return tmp - buf;
+}
+
+/* return the length of the text that is the stem of a file name */
+static int get_stem_from_file_name(const char *const buf)
+{
+	const char *tmp = strchr(buf + 1, '/');
+
+	if (!tmp)
+		return 0;
+	return tmp - buf;
+}
+
+/* find the stem of a file spec, returns the index into stem_arr for a new
+ * or existing stem, (or -1 if there is no possible stem - IE for a file in
+ * the root directory or a regex that is too complex for us). */
+static int find_stem_from_spec(struct saved_data *data, const char *buf)
+{
+	int i, num = data->num_stems;
+	int stem_len = get_stem_from_spec(buf);
+
+	if (!stem_len)
+		return -1;
+	for (i = 0; i < num; i++) {
+		if (stem_len == data->stem_arr[i].len
+		    && !strncmp(buf, data->stem_arr[i].buf, stem_len))
+			return i;
+	}
+	if (data->alloc_stems == num) {
+		stem_t *tmp_arr;
+		data->alloc_stems = data->alloc_stems * 2 + 16;
+		tmp_arr = (stem_t *) realloc(data->stem_arr,
+				  sizeof(stem_t) * data->alloc_stems);
+		if (!tmp_arr)
+			return -1;
+		data->stem_arr = tmp_arr;
+	}
+	data->stem_arr[num].len = stem_len;
+	data->stem_arr[num].buf = (char *) malloc(stem_len + 1);
+	if (!data->stem_arr[num].buf)
+		return -1;
+	memcpy(data->stem_arr[num].buf, buf, stem_len);
+	data->stem_arr[num].buf[stem_len] = '\0';
+	data->num_stems++;
+	buf += stem_len;
+	return num;
+}
+
+/* find the stem of a file name, returns the index into stem_arr (or -1 if
+ * there is no match - IE for a file in the root directory or a regex that is
+ * too complex for us).  Makes buf point to the text AFTER the stem. */
+static int find_stem_from_file(struct saved_data *data, const char **buf)
+{
+	int i;
+	int stem_len = get_stem_from_file_name(*buf);
+
+	if (!stem_len)
+		return -1;
+	for (i = 0; i < data->num_stems; i++) {
+		if (stem_len == data->stem_arr[i].len
+		    && !strncmp(*buf, data->stem_arr[i].buf, stem_len)) {
+			*buf += stem_len;
+			return i;
+		}
+	}
+	return -1;
+}
+
+/*
+ * Warn about duplicate specifications.
+ */
+static int nodups_specs(struct saved_data *data, const char *path)
+{
+	int rc = 0;
+	unsigned int ii, jj;
+	struct spec *curr_spec, *spec_arr = data->spec_arr;
+
+	for (ii = 0; ii < data->nspec; ii++) {
+		curr_spec = &spec_arr[ii];
+		for (jj = ii + 1; jj < data->nspec; jj++) {
+			if ((!strcmp
+			     (spec_arr[jj].regex_str, curr_spec->regex_str))
+			    && (!spec_arr[jj].mode || !curr_spec->mode
+				|| spec_arr[jj].mode == curr_spec->mode)) {
+				rc = -1;
+				errno = EINVAL;
+				if (strcmp
+				    (spec_arr[jj].lr.ctx_raw,
+				     curr_spec->lr.ctx_raw)) {
+					selinux_log
+						(SELINUX_ERROR,
+						 "%s: Multiple different specifications for %s  (%s and %s).\n",
+						 path, curr_spec->regex_str,
+						 spec_arr[jj].lr.ctx_raw,
+						 curr_spec->lr.ctx_raw);
+				} else {
+					selinux_log
+						(SELINUX_ERROR,
+						 "%s: Multiple same specifications for %s.\n",
+						 path, curr_spec->regex_str);
+				}
+			}
+		}
+	}
+	return rc;
+}
+
+/* Determine if the regular expression specification has any meta characters. */
+static void spec_hasMetaChars(struct spec *spec)
+{
+	char *c;
+	size_t len;
+	char *end;
+
+	c = spec->regex_str;
+	len = strlen(spec->regex_str);
+	end = c + len;
+
+	spec->hasMetaChars = 0;
+	spec->prefix_len = len;
+
+	/* Look at each character in the RE specification string for a 
+	 * meta character. Return when any meta character reached. */
+	while (c != end) {
+		switch (*c) {
+		case '.':
+		case '^':
+		case '$':
+		case '?':
+		case '*':
+		case '+':
+		case '|':
+		case '[':
+		case '(':
+		case '{':
+			spec->hasMetaChars = 1;
+			spec->prefix_len = c - spec->regex_str;
+			return;
+		case '\\':	/* skip the next character */
+			c++;
+			break;
+		default:
+			break;
+
+		}
+		c++;
+	}
+	return;
+}
+
+static int compile_regex(struct saved_data *data, spec_t *spec, char **errbuf)
+{
+	char *reg_buf, *anchored_regex, *cp;
+	stem_t *stem_arr = data->stem_arr;
+	size_t len;
+	int regerr;
+
+	if (spec->regcomp)
+		return 0; /* already done */
+
+	data->ncomp++; /* how many compiled regexes required */
+
+	/* Skip the fixed stem. */
+	reg_buf = spec->regex_str;
+	if (spec->stem_id >= 0)
+		reg_buf += stem_arr[spec->stem_id].len;
+
+	/* Anchor the regular expression. */
+	len = strlen(reg_buf);
+	cp = anchored_regex = (char *) malloc(len + 3);
+	if (!anchored_regex)
+		return -1;
+	/* Create ^...$ regexp.  */
+	*cp++ = '^';
+	memcpy(cp, reg_buf, len);
+	cp += len;
+	*cp++ = '$';
+	*cp = '\0';
+
+	/* Compile the regular expression. */
+	regerr = regcomp(&spec->regex, anchored_regex, 
+			 REG_EXTENDED | REG_NOSUB);
+	if (regerr != 0) {
+		size_t errsz = 0;
+		errsz = regerror(regerr, &spec->regex, NULL, 0);
+		if (errsz && errbuf)
+			*errbuf = (char *) malloc(errsz);
+		if (errbuf && *errbuf)
+			(void)regerror(regerr, &spec->regex,
+				       *errbuf, errsz);
+
+		free(anchored_regex);
+		return -1;
+	}
+	free(anchored_regex);
+
+	/* Done. */
+	spec->regcomp = 1;
+
+	return 0;
+}
+
+
+static int process_line(struct selabel_handle *rec,
+			const char *path, const char *prefix,
+			char *line_buf, int pass, unsigned lineno)
+{
+	int items, len;
+	char buf1[BUFSIZ], buf2[BUFSIZ], buf3[BUFSIZ];
+	char *buf_p, *regex = buf1, *type = buf2, *context = buf3;
+	struct saved_data *data = (struct saved_data *)rec->data;
+	spec_t *spec_arr = data->spec_arr;
+	unsigned int nspec = data->nspec;
+
+	len = strlen(line_buf);
+	if (line_buf[len - 1] == '\n')
+		line_buf[len - 1] = 0;
+	buf_p = line_buf;
+	while (isspace(*buf_p))
+		buf_p++;
+	/* Skip comment lines and empty lines. */
+	if (*buf_p == '#' || *buf_p == 0)
+		return 0;
+	items = sscanf(line_buf, "%255s %255s %255s", regex, type, context);
+	if (items < 2) {
+		selinux_log(SELINUX_WARNING,
+			    "%s:  line %d is missing fields, skipping\n", path,
+			    lineno);
+		return 0;
+	} else if (items == 2) {
+		/* The type field is optional. */
+		context = type;
+		type = NULL;
+	}
+
+	len = get_stem_from_spec(regex);
+	if (len && prefix && strncmp(prefix, regex, len)) {
+		/* Stem of regex does not match requested prefix, discard. */
+		return 0;
+	}
+
+	if (pass == 1) {
+		/* On the second pass, process and store the specification in spec. */
+		char *errbuf = NULL;
+		spec_arr[nspec].stem_id = find_stem_from_spec(data, regex);
+		spec_arr[nspec].regex_str = strdup(regex);
+		if (!spec_arr[nspec].regex_str) {
+			selinux_log(SELINUX_WARNING,
+				   "%s:  out of memory at line %d on regex %s\n",
+				   path, lineno, regex);
+			return -1;
+
+		}
+		if (rec->validating && compile_regex(data, &spec_arr[nspec], &errbuf)) {
+			selinux_log(SELINUX_WARNING,
+				   "%s:  line %d has invalid regex %s:  %s\n",
+				   path, lineno, regex,
+				   (errbuf ? errbuf : "out of memory"));
+		}
+
+		/* Convert the type string to a mode format */
+		spec_arr[nspec].mode = 0;
+		if (!type)
+			goto skip_type;
+		spec_arr[nspec].type_str = strdup(type);
+		len = strlen(type);
+		if (type[0] != '-' || len != 2) {
+			selinux_log(SELINUX_WARNING,
+				    "%s:  line %d has invalid file type %s\n",
+				    path, lineno, type);
+			return 0;
+		}
+		switch (type[1]) {
+		case 'b':
+			spec_arr[nspec].mode = S_IFBLK;
+			break;
+		case 'c':
+			spec_arr[nspec].mode = S_IFCHR;
+			break;
+		case 'd':
+			spec_arr[nspec].mode = S_IFDIR;
+			break;
+		case 'p':
+			spec_arr[nspec].mode = S_IFIFO;
+			break;
+		case 'l':
+			spec_arr[nspec].mode = S_IFLNK;
+			break;
+		case 's':
+			spec_arr[nspec].mode = S_IFSOCK;
+			break;
+		case '-':
+			spec_arr[nspec].mode = S_IFREG;
+			break;
+		default:
+			selinux_log(SELINUX_WARNING,
+				    "%s:  line %d has invalid file type %s\n",
+				    path, lineno, type);
+			return 0;
+		}
+
+	skip_type:
+		spec_arr[nspec].lr.ctx_raw = strdup(context);
+
+		if (strcmp(context, "<<none>>") && rec->validating) {
+			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
+				selinux_log(SELINUX_WARNING,
+					    "%s:  line %d has invalid context %s\n",
+					    path, lineno, spec_arr[nspec].lr.ctx_raw);
+			}
+		}
+
+		/* Determine if specification has 
+		 * any meta characters in the RE */
+		spec_hasMetaChars(&spec_arr[nspec]);
+	}
+
+	data->nspec = ++nspec;
+	return 0;
+}
+
+static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		unsigned n)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	const char *path = NULL;
+	const char *prefix = NULL;
+	FILE *fp;
+	FILE *localfp = NULL;
+	FILE *homedirfp = NULL;
+	char local_path[PATH_MAX + 1];
+	char homedir_path[PATH_MAX + 1];
+	char line_buf[BUFSIZ];
+	unsigned int lineno, pass, i, j, maxnspec;
+	spec_t *spec_copy = NULL;
+	int status = -1, baseonly = 0;
+	struct stat sb;
+
+	/* Process arguments */
+	while (n--)
+		switch(opts[n].type) {
+		case SELABEL_OPT_PATH:
+			path = opts[n].value;
+			break;
+		case SELABEL_OPT_SUBSET:
+			prefix = opts[n].value;
+			break;
+		case SELABEL_OPT_BASEONLY:
+			baseonly = !!opts[n].value;
+			break;
+		}
+
+	/* Open the specification file. */
+	if ((fp = fopen(path, "r")) == NULL)
+		return -1;
+
+	if (fstat(fileno(fp), &sb) < 0)
+		return -1;
+	if (!S_ISREG(sb.st_mode)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (!baseonly) {
+		snprintf(homedir_path, sizeof(homedir_path), "%s.homedirs",
+			 path);
+		homedirfp = fopen(homedir_path, "r");
+
+		snprintf(local_path, sizeof(local_path), "%s.local", path);
+		localfp = fopen(local_path, "r");
+	}
+
+	/* 
+	 * Perform two passes over the specification file.
+	 * The first pass counts the number of specifications and
+	 * performs simple validation of the input.  At the end
+	 * of the first pass, the spec array is allocated.
+	 * The second pass performs detailed validation of the input
+	 * and fills in the spec array.
+	 */
+	maxnspec = UINT_MAX / sizeof(spec_t);
+	for (pass = 0; pass < 2; pass++) {
+		lineno = 0;
+		data->nspec = 0;
+		data->ncomp = 0;
+		while (fgets(line_buf, sizeof line_buf - 1, fp)
+		       && data->nspec < maxnspec) {
+			if (process_line(rec, path, prefix, line_buf,
+					 pass, ++lineno) != 0)
+				goto finish;
+		}
+		if (pass == 1) {
+			status = nodups_specs(data, path);
+			if (status)
+				goto finish;
+		}
+		lineno = 0;
+		if (homedirfp)
+			while (fgets(line_buf, sizeof line_buf - 1, homedirfp)
+			       && data->nspec < maxnspec) {
+				if (process_line
+				    (rec, homedir_path, prefix,
+				     line_buf, pass, ++lineno) != 0)
+					goto finish;
+			}
+
+		lineno = 0;
+		if (localfp)
+			while (fgets(line_buf, sizeof line_buf - 1, localfp)
+			       && data->nspec < maxnspec) {
+				if (process_line
+				    (rec, local_path, prefix, line_buf,
+				     pass, ++lineno) != 0)
+					goto finish;
+			}
+
+		if (pass == 0) {
+			if (data->nspec == 0) {
+				status = 0;
+				goto finish;
+			}
+			if (NULL == (data->spec_arr =
+				     (spec_t *) malloc(sizeof(spec_t) * data->nspec)))
+				goto finish;
+			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
+			maxnspec = data->nspec;
+			rewind(fp);
+			if (homedirfp)
+				rewind(homedirfp);
+			if (localfp)
+				rewind(localfp);
+		}
+	}
+
+	/* Move exact pathname specifications to the end. */
+	spec_copy = (spec_t *) malloc(sizeof(spec_t) * data->nspec);
+	if (!spec_copy)
+		goto finish;
+	j = 0;
+	for (i = 0; i < data->nspec; i++)
+		if (data->spec_arr[i].hasMetaChars)
+			memcpy(&spec_copy[j++],
+			       &data->spec_arr[i], sizeof(spec_t));
+	for (i = 0; i < data->nspec; i++)
+		if (!data->spec_arr[i].hasMetaChars)
+			memcpy(&spec_copy[j++],
+			       &data->spec_arr[i], sizeof(spec_t));
+	free(data->spec_arr);
+	data->spec_arr = spec_copy;
+
+	status = 0;
+finish:
+	fclose(fp);
+	if (data->spec_arr != spec_copy)
+		free(data->spec_arr);
+	if (homedirfp)
+		fclose(homedirfp);
+	if (localfp)
+		fclose(localfp);
+	return status;
+}
+
+/*
+ * Backend interface routines
+ */
+static void closef(struct selabel_handle *rec)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	struct spec *spec;
+	struct stem *stem;
+	unsigned int i;
+
+	for (i = 0; i < data->nspec; i++) {
+		spec = &data->spec_arr[i];
+		free(spec->regex_str);
+		free(spec->type_str);
+		free(spec->lr.ctx_raw);
+		free(spec->lr.ctx_trans);
+		if (spec->regcomp)
+			regfree(&spec->regex);
+	}
+
+	for (i = 0; i < (unsigned int)data->num_stems; i++) {
+		stem = &data->stem_arr[i];
+		free(stem->buf);
+	}
+
+	if (data->spec_arr)
+		free(data->spec_arr);
+	if (data->stem_arr)
+		free(data->stem_arr);
+	
+	free(data);
+}
+
+static struct selabel_lookup_rec *lookup_common(struct selabel_handle *rec,
+						const char *key, int type,
+						bool partial)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	spec_t *spec_arr = data->spec_arr;
+	int i, rc, file_stem;
+	mode_t mode = (mode_t)type;
+	const char *buf;
+	struct selabel_lookup_rec *ret = NULL;
+	char *clean_key = NULL;
+	const char *prev_slash, *next_slash;
+	unsigned int sofar = 0;
+	size_t keylen = strlen(key);
+
+	if (!data->nspec) {
+		errno = ENOENT;
+		goto finish;
+	}
+
+	/* Remove duplicate slashes */
+	if ((next_slash = strstr(key, "//"))) {
+		clean_key = (char *) malloc(strlen(key) + 1);
+		if (!clean_key)
+			goto finish;
+		prev_slash = key;
+		while (next_slash) {
+			memcpy(clean_key + sofar, prev_slash, next_slash - prev_slash);
+			sofar += next_slash - prev_slash;
+			prev_slash = next_slash + 1;
+			next_slash = strstr(prev_slash, "//");
+		}
+		strcpy(clean_key + sofar, prev_slash);
+		key = clean_key;
+	}
+
+	buf = key;
+	file_stem = find_stem_from_file(data, &buf);
+	mode &= S_IFMT;
+
+	/* 
+	 * Check for matching specifications in reverse order, so that
+	 * the last matching specification is used.
+	 */
+	for (i = data->nspec - 1; i >= 0; i--) {
+		/* if the spec in question matches no stem or has the same
+		 * stem as the file AND if the spec in question has no mode
+		 * specified or if the mode matches the file mode then we do
+		 * a regex check        */
+		if ((spec_arr[i].stem_id == -1
+		     || spec_arr[i].stem_id == file_stem)
+		    && (!mode || !spec_arr[i].mode
+			|| mode == spec_arr[i].mode)) {
+			if (compile_regex(data, &spec_arr[i], NULL) < 0)
+				goto finish;
+			if (spec_arr[i].stem_id == -1)
+				rc = regexec(&spec_arr[i].regex, key, 0, 0, 0);
+			else
+				rc = regexec(&spec_arr[i].regex, buf, 0, 0, 0);
+
+			if (rc == 0) {
+				spec_arr[i].matches++;
+				break;
+			}
+
+			if (partial) {
+				/*
+				 * We already checked above to see if the
+				 * key has any direct match.  Now we just need
+				 * to check for partial matches.
+				 * Since POSIX regex functions do not support
+				 * partial match, we crudely approximate it
+				 * via a prefix match.
+				 * This is imprecise and could yield
+				 * false positives or negatives but
+				 * appears to work with our current set of
+				 * regex strings.
+				 * Convert to using pcre partial match
+				 * if/when pcre becomes available in Android.
+				 */
+				if (spec_arr[i].prefix_len > 1 &&
+				    !strncmp(key, spec_arr[i].regex_str,
+					     keylen < spec_arr[i].prefix_len ?
+					     keylen : spec_arr[i].prefix_len))
+					break;
+			}
+
+			if (rc == REG_NOMATCH)
+				continue;
+			/* else it's an error */
+			goto finish;
+		}
+	}
+
+	if (i < 0 || strcmp(spec_arr[i].lr.ctx_raw, "<<none>>") == 0) {
+		/* No matching specification. */
+		errno = ENOENT;
+		goto finish;
+	}
+
+	ret = &spec_arr[i].lr;
+
+finish:
+	free(clean_key);
+	return ret;
+}
+
+static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
+					 const char *key, int type)
+{
+	return lookup_common(rec, key, type, false);
+}
+
+static bool partial_match(struct selabel_handle *rec, const char *key)
+{
+	return lookup_common(rec, key, 0, true) ? true : false;
+}
+
+static void stats(struct selabel_handle *rec)
+{
+	struct saved_data *data = (struct saved_data *)rec->data;
+	unsigned int i, nspec = data->nspec;
+	spec_t *spec_arr = data->spec_arr;
+
+	for (i = 0; i < nspec; i++) {
+		if (spec_arr[i].matches == 0) {
+			if (spec_arr[i].type_str) {
+				selinux_log(SELINUX_WARNING,
+				    "Warning!  No matches for (%s, %s, %s)\n",
+				    spec_arr[i].regex_str,
+				    spec_arr[i].type_str,
+				    spec_arr[i].lr.ctx_raw);
+			} else {
+				selinux_log(SELINUX_WARNING,
+				    "Warning!  No matches for (%s, %s)\n",
+				    spec_arr[i].regex_str,
+				    spec_arr[i].lr.ctx_raw);
+			}
+		}
+	}
+}
+
+int selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		      unsigned nopts)
+{
+	struct saved_data *data;
+
+	data = (struct saved_data *)malloc(sizeof(*data));
+	if (!data)
+		return -1;
+	memset(data, 0, sizeof(*data));
+
+	rec->data = data;
+	rec->func_close = &closef;
+	rec->func_stats = &stats;
+	rec->func_lookup = &lookup;
+	rec->func_partial_match = &partial_match;
+
+	return init(rec, opts, nopts);
+}
diff --git a/distrib/libselinux/src/label_internal.h b/distrib/libselinux/src/label_internal.h
new file mode 100644
index 0000000..e44e3cc
--- /dev/null
+++ b/distrib/libselinux/src/label_internal.h
@@ -0,0 +1,73 @@
+/*
+ * This file describes the internal interface used by the labeler
+ * for calling the user-supplied memory allocation, validation,
+ * and locking routine.
+ *
+ * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
+ */
+#ifndef _SELABEL_INTERNAL_H_
+#define _SELABEL_INTERNAL_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <selinux/selinux.h>
+#include <selinux/label.h>
+#include "dso.h"
+
+/*
+ * Installed backends
+ */
+int selabel_file_init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		      unsigned nopts) hidden;
+int selabel_media_init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		      unsigned nopts) hidden;
+int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts,
+		   unsigned nopts) hidden;
+int selabel_db_init(struct selabel_handle *rec,
+		    const struct selinux_opt *opts, unsigned nopts) hidden;
+int selabel_property_init(struct selabel_handle *rec,
+			  const struct selinux_opt *opts, unsigned nopts) hidden;
+
+/*
+ * Labeling internal structures
+ */
+struct selabel_sub {
+	char *src;
+	int slen;
+	char *dst;
+	struct selabel_sub *next;
+};
+
+struct selabel_lookup_rec {
+	char * ctx_raw;
+	char * ctx_trans;
+	int validated;
+};
+
+struct selabel_handle {
+	/* arguments that were passed to selabel_open */
+	unsigned int backend;
+	int validating;
+
+	/* labeling operations */
+	struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h,
+						   const char *key, int type);
+	void (*func_close) (struct selabel_handle *h);
+	void (*func_stats) (struct selabel_handle *h);
+	bool (*func_partial_match) (struct selabel_handle *h, const char *key);
+
+	/* supports backend-specific state information */
+	void *data;
+
+	/* substitution support */
+	struct selabel_sub *subs;
+};
+
+/*
+ * Validation function
+ */
+extern int
+selabel_validate(struct selabel_handle *rec,
+		 struct selabel_lookup_rec *contexts) hidden;
+
+#endif				/* _SELABEL_INTERNAL_H_ */
diff --git a/distrib/libselinux/src/lgetfilecon.c b/distrib/libselinux/src/lgetfilecon.c
new file mode 100644
index 0000000..22851a4
--- /dev/null
+++ b/distrib/libselinux/src/lgetfilecon.c
@@ -0,0 +1,50 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+int lgetfilecon(const char *path, char ** context)
+{
+	char *buf;
+	ssize_t size;
+	ssize_t ret;
+
+	size = INITCONTEXTLEN + 1;
+	buf = malloc(size);
+	if (!buf)
+		return -1;
+	memset(buf, 0, size);
+
+	ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
+	if (ret < 0 && errno == ERANGE) {
+		char *newbuf;
+
+		size = lgetxattr(path, XATTR_NAME_SELINUX, NULL, 0);
+		if (size < 0)
+			goto out;
+
+		size++;
+		newbuf = realloc(buf, size);
+		if (!newbuf)
+			goto out;
+
+		buf = newbuf;
+		memset(buf, 0, size);
+		ret = lgetxattr(path, XATTR_NAME_SELINUX, buf, size - 1);
+	}
+      out:
+	if (ret == 0) {
+		/* Re-map empty attribute values to errors. */
+		errno = EOPNOTSUPP;
+		ret = -1;
+	}
+	if (ret < 0)
+		free(buf);
+	else
+		*context = buf;
+	return ret;
+}
diff --git a/distrib/libselinux/src/load_policy.c b/distrib/libselinux/src/load_policy.c
new file mode 100644
index 0000000..d103365
--- /dev/null
+++ b/distrib/libselinux/src/load_policy.c
@@ -0,0 +1,41 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/utsname.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include "selinux_internal.h"
+#include <dlfcn.h>
+#include "policy.h"
+#include <limits.h>
+#include "callbacks.h"
+
+int security_load_policy(void *data, size_t len)
+{
+	char path[PATH_MAX];
+	int fd, ret;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/load", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	ret = write(fd, data, len);
+	close(fd);
+	if (ret < 0)
+		return -1;
+	return 0;
+}
+
+hidden_def(security_load_policy)
diff --git a/distrib/libselinux/src/lsetfilecon.c b/distrib/libselinux/src/lsetfilecon.c
new file mode 100644
index 0000000..7147f9e
--- /dev/null
+++ b/distrib/libselinux/src/lsetfilecon.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+int lsetfilecon(const char *path, const char *context)
+{
+	return lsetxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,
+			 0);
+}
+
diff --git a/distrib/libselinux/src/mapping.c b/distrib/libselinux/src/mapping.c
new file mode 100644
index 0000000..f9858ce
--- /dev/null
+++ b/distrib/libselinux/src/mapping.c
@@ -0,0 +1,195 @@
+/*
+ * Class and permission mappings.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <selinux/selinux.h>
+#include <selinux/avc.h>
+#include "mapping.h"
+
+/*
+ * Class and permission mappings
+ */
+
+struct selinux_mapping {
+	security_class_t value; /* real, kernel value */
+	unsigned num_perms;
+	access_vector_t perms[sizeof(access_vector_t) * 8];
+};
+
+static struct selinux_mapping *current_mapping = NULL;
+static security_class_t current_mapping_size = 0;
+
+/*
+ * Mapping setting function
+ */
+
+int
+selinux_set_mapping(struct security_class_mapping *map)
+{
+	size_t size = sizeof(struct selinux_mapping);
+	security_class_t i, j;
+	unsigned k;
+
+	free(current_mapping);
+	current_mapping = NULL;
+	current_mapping_size = 0;
+
+	if (avc_reset() < 0)
+		goto err;
+
+	/* Find number of classes in the input mapping */
+	if (!map) {
+		errno = EINVAL;
+		goto err;
+	}
+	i = 0;
+	while (map[i].name)
+		i++;
+
+	/* Allocate space for the class records, plus one for class zero */
+	current_mapping = (struct selinux_mapping *)calloc(++i, size);
+	if (!current_mapping)
+		goto err;
+
+	/* Store the raw class and permission values */
+	j = 0;
+	while (map[j].name) {
+		struct security_class_mapping *p_in = map + (j++);
+		struct selinux_mapping *p_out = current_mapping + j;
+
+		p_out->value = string_to_security_class(p_in->name);
+		if (!p_out->value)
+			goto err2;
+
+		k = 0;
+		while (p_in->perms && p_in->perms[k]) {
+			/* An empty permission string skips ahead */
+			if (!*p_in->perms[k]) {
+				k++;
+				continue;
+			}
+			p_out->perms[k] = string_to_av_perm(p_out->value,
+							    p_in->perms[k]);
+			if (!p_out->perms[k])
+				goto err2;
+			k++;
+		}
+		p_out->num_perms = k;
+	}
+
+	/* Set the mapping size here so the above lookups are "raw" */
+	current_mapping_size = i;
+	return 0;
+err2:
+	free(current_mapping);
+	current_mapping = NULL;
+	current_mapping_size = 0;
+err:
+	return -1;
+}
+
+/*
+ * Get real, kernel values from mapped values
+ */
+
+security_class_t
+unmap_class(security_class_t tclass)
+{
+	if (tclass < current_mapping_size)
+		return current_mapping[tclass].value;
+
+	assert(current_mapping_size == 0);
+	return tclass;
+}
+
+access_vector_t
+unmap_perm(security_class_t tclass, access_vector_t tperm)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t kperm = 0;
+
+		for (i=0; i<current_mapping[tclass].num_perms; i++)
+			if (tperm & (1<<i)) {
+				assert(current_mapping[tclass].perms[i]);
+				kperm |= current_mapping[tclass].perms[i];
+				tperm &= ~(1<<i);
+			}
+		assert(tperm == 0);
+		return kperm;
+	}
+
+	assert(current_mapping_size == 0);
+	return tperm;
+}
+
+/*
+ * Get mapped values from real, kernel values
+ */
+
+security_class_t
+map_class(security_class_t kclass)
+{
+	security_class_t i;
+
+	for (i=0; i<current_mapping_size; i++)
+		if (current_mapping[i].value == kclass)
+			return i;
+
+	assert(current_mapping_size == 0);
+	return kclass;
+}
+
+access_vector_t
+map_perm(security_class_t tclass, access_vector_t kperm)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t tperm = 0;
+
+		for (i=0; i<current_mapping[tclass].num_perms; i++)
+			if (kperm & current_mapping[tclass].perms[i]) {
+				tperm |= 1<<i;
+				kperm &= ~current_mapping[tclass].perms[i];
+			}
+		assert(kperm == 0);
+		return tperm;
+	}
+
+	assert(current_mapping_size == 0);
+	return kperm;
+}
+
+void
+map_decision(security_class_t tclass, struct av_decision *avd)
+{
+	if (tclass < current_mapping_size) {
+		unsigned i;
+		access_vector_t result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->allowed & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->allowed = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->decided & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->decided = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->auditallow & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->auditallow = result;
+
+		for (i=0, result=0; i<current_mapping[tclass].num_perms; i++)
+			if (avd->auditdeny & current_mapping[tclass].perms[i])
+				result |= 1<<i;
+		avd->auditdeny = result;
+	}
+}
diff --git a/distrib/libselinux/src/mapping.h b/distrib/libselinux/src/mapping.h
new file mode 100644
index 0000000..b96756b
--- /dev/null
+++ b/distrib/libselinux/src/mapping.h
@@ -0,0 +1,41 @@
+/*
+ * This file describes the class and permission mappings used to 
+ * hide the kernel numbers from userspace by allowing userspace object
+ * managers to specify a list of classes and permissions.
+ */
+#ifndef _SELINUX_MAPPING_H_
+#define _SELINUX_MAPPING_H_
+
+#include <selinux/selinux.h>
+
+/*
+ * Get real, kernel values from mapped values
+ */
+
+extern security_class_t
+unmap_class(security_class_t tclass);
+
+extern access_vector_t
+unmap_perm(security_class_t tclass, access_vector_t tperm);
+
+/*
+ * Get mapped values from real, kernel values
+ */
+
+extern security_class_t
+map_class(security_class_t kclass);
+
+extern access_vector_t
+map_perm(security_class_t tclass, access_vector_t kperm);
+
+extern void
+map_decision(security_class_t tclass, struct av_decision *avd);
+
+/*mapping is not used for embedded build*/
+#ifdef DISABLE_AVC 
+#define unmap_perm(x,y) y
+#define unmap_class(x) x
+#define map_decision(x,y) 
+#endif
+
+#endif				/* _SELINUX_MAPPING_H_ */
diff --git a/distrib/libselinux/src/policy.h b/distrib/libselinux/src/policy.h
new file mode 100644
index 0000000..92a416e
--- /dev/null
+++ b/distrib/libselinux/src/policy.h
@@ -0,0 +1,28 @@
+#ifndef _POLICY_H_
+#define _POLICY_H_
+
+/* Private definitions used internally by libselinux. */
+
+/* xattr name for SELinux attributes. */
+#define XATTR_NAME_SELINUX "security.selinux"
+
+/* Initial length guess for getting contexts. */
+#define INITCONTEXTLEN 255
+
+/* selinuxfs magic number */
+#define SELINUX_MAGIC 0xf97cff8c
+
+/* Preferred selinuxfs mount point directory paths. */
+#define SELINUXMNT "/sys/fs/selinux"
+#define OLDSELINUXMNT "/selinux"
+
+/* selinuxfs filesystem type string. */
+#define SELINUXFS "selinuxfs"
+
+/* selinuxfs mount point determined at runtime */
+extern char *selinux_mnt;
+
+/* First version of policy supported in mainline Linux. */
+#define DEFAULT_POLICY_VERSION 15
+
+#endif
diff --git a/distrib/libselinux/src/policyvers.c b/distrib/libselinux/src/policyvers.c
new file mode 100644
index 0000000..284a7f7
--- /dev/null
+++ b/distrib/libselinux/src/policyvers.c
@@ -0,0 +1,45 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include <stdio.h>
+#include "policy.h"
+#include "dso.h"
+#include <limits.h>
+
+int security_policyvers(void)
+{
+	int fd, ret;
+	char path[PATH_MAX];
+	char buf[20];
+	unsigned vers = DEFAULT_POLICY_VERSION;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/policyvers", selinux_mnt);
+	fd = open(path, O_RDONLY);
+	if (fd < 0) {
+		if (errno == ENOENT)
+			return vers;
+		else
+			return -1;
+	}
+	memset(buf, 0, sizeof buf);
+	ret = read(fd, buf, sizeof buf - 1);
+	close(fd);
+	if (ret < 0)
+		return -1;
+
+	if (sscanf(buf, "%u", &vers) != 1)
+		return -1;
+
+	return vers;
+}
+
+hidden_def(security_policyvers)
diff --git a/distrib/libselinux/src/procattr.c b/distrib/libselinux/src/procattr.c
new file mode 100644
index 0000000..f350808
--- /dev/null
+++ b/distrib/libselinux/src/procattr.c
@@ -0,0 +1,163 @@
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+#ifdef HOST
+static pid_t gettid(void)
+{
+	return syscall(__NR_gettid);
+}
+#endif
+
+static int getprocattrcon(char ** context,
+			  pid_t pid, const char *attr)
+{
+	char *path, *buf;
+	size_t size;
+	int fd, rc;
+	ssize_t ret;
+	pid_t tid;
+	int errno_hold;
+
+	if (pid > 0)
+		rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
+	else {
+		tid = gettid();
+		rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
+	}
+	if (rc < 0)
+		return -1;
+
+	fd = open(path, O_RDONLY);
+	free(path);
+	if (fd < 0)
+		return -1;
+
+	size = selinux_page_size;
+	buf = malloc(size);
+	if (!buf) {
+		ret = -1;
+		goto out;
+	}
+	memset(buf, 0, size);
+
+	do {
+		ret = read(fd, buf, size - 1);
+	} while (ret < 0 && errno == EINTR);
+	if (ret < 0)
+		goto out2;
+
+	if (ret == 0) {
+		*context = NULL;
+		goto out2;
+	}
+
+	*context = strdup(buf);
+	if (!(*context)) {
+		ret = -1;
+		goto out2;
+	}
+	ret = 0;
+      out2:
+	free(buf);
+      out:
+	errno_hold = errno;
+	close(fd);
+	errno = errno_hold;
+	return ret;
+}
+
+static int setprocattrcon(const char * context,
+			  pid_t pid, const char *attr)
+{
+	char *path;
+	int fd, rc;
+	pid_t tid;
+	ssize_t ret;
+	int errno_hold;
+
+	if (pid > 0)
+		rc = asprintf(&path, "/proc/%d/attr/%s", pid, attr);
+	else {
+		tid = gettid();
+		rc = asprintf(&path, "/proc/self/task/%d/attr/%s", tid, attr);
+	}
+	if (rc < 0)
+		return -1;
+
+	fd = open(path, O_RDWR);
+	free(path);
+	if (fd < 0)
+		return -1;
+	if (context)
+		do {
+			ret = write(fd, context, strlen(context) + 1);
+		} while (ret < 0 && errno == EINTR);
+	else
+		do {
+			ret = write(fd, NULL, 0);	/* clear */
+		} while (ret < 0 && errno == EINTR);
+	errno_hold = errno;
+	close(fd);
+	errno = errno_hold;
+	if (ret < 0)
+		return -1;
+	else
+		return 0;
+}
+
+#define getselfattr_def(fn, attr) \
+	int get##fn(char **c) \
+	{ \
+		return getprocattrcon(c, 0, #attr); \
+	}
+
+#define setselfattr_def(fn, attr) \
+	int set##fn(const char * c) \
+	{ \
+		return setprocattrcon(c, 0, #attr); \
+	}
+
+#define all_selfattr_def(fn, attr) \
+	getselfattr_def(fn, attr)	 \
+	setselfattr_def(fn, attr)
+
+#define getpidattr_def(fn, attr) \
+	int get##fn(pid_t pid, char **c)	\
+	{ \
+		return getprocattrcon(c, pid, #attr); \
+	}
+
+all_selfattr_def(con, current)
+    getpidattr_def(pidcon, current)
+    getselfattr_def(prevcon, prev)
+    all_selfattr_def(execcon, exec)
+    all_selfattr_def(fscreatecon, fscreate)
+    all_selfattr_def(sockcreatecon, sockcreate)
+    all_selfattr_def(keycreatecon, keycreate)
+
+    hidden_def(getcon_raw)
+    hidden_def(getcon)
+    hidden_def(getexeccon_raw)
+    hidden_def(getfilecon_raw)
+    hidden_def(getfilecon)
+    hidden_def(getfscreatecon_raw)
+    hidden_def(getkeycreatecon_raw)
+    hidden_def(getpeercon_raw)
+    hidden_def(getpidcon_raw)
+    hidden_def(getprevcon_raw)
+    hidden_def(getprevcon)
+    hidden_def(getsockcreatecon_raw)
+    hidden_def(setcon_raw)
+    hidden_def(setexeccon_raw)
+    hidden_def(setexeccon)
+    hidden_def(setfilecon_raw)
+    hidden_def(setfscreatecon_raw)
+    hidden_def(setkeycreatecon_raw)
+    hidden_def(setsockcreatecon_raw)
diff --git a/distrib/libselinux/src/selinux_internal.h b/distrib/libselinux/src/selinux_internal.h
new file mode 100644
index 0000000..5087bb6
--- /dev/null
+++ b/distrib/libselinux/src/selinux_internal.h
@@ -0,0 +1,132 @@
+#include <selinux/selinux.h>
+#include <pthread.h>
+#include "dso.h"
+
+hidden_proto(selinux_mkload_policy)
+    hidden_proto(set_selinuxmnt)
+    hidden_proto(security_disable)
+    hidden_proto(security_policyvers)
+    hidden_proto(security_load_policy)
+    hidden_proto(security_get_boolean_active)
+    hidden_proto(security_get_boolean_names)
+    hidden_proto(security_set_boolean)
+    hidden_proto(security_commit_booleans)
+    hidden_proto(security_check_context)
+    hidden_proto(security_check_context_raw)
+    hidden_proto(security_canonicalize_context)
+    hidden_proto(security_canonicalize_context_raw)
+    hidden_proto(security_compute_av)
+    hidden_proto(security_compute_av_raw)
+    hidden_proto(security_compute_av_flags)
+    hidden_proto(security_compute_av_flags_raw)
+    hidden_proto(security_compute_user)
+    hidden_proto(security_compute_user_raw)
+    hidden_proto(security_compute_create)
+    hidden_proto(security_compute_create_raw)
+    hidden_proto(security_compute_member_raw)
+    hidden_proto(security_compute_relabel_raw)
+    hidden_proto(is_selinux_enabled)
+    hidden_proto(is_selinux_mls_enabled)
+    hidden_proto(freecon)
+    hidden_proto(freeconary)
+    hidden_proto(getprevcon)
+    hidden_proto(getprevcon_raw)
+    hidden_proto(getcon)
+    hidden_proto(getcon_raw)
+    hidden_proto(setcon_raw)
+    hidden_proto(getpeercon_raw)
+    hidden_proto(getpidcon_raw)
+    hidden_proto(getexeccon_raw)
+    hidden_proto(getfilecon)
+    hidden_proto(getfilecon_raw)
+    hidden_proto(lgetfilecon_raw)
+    hidden_proto(fgetfilecon_raw)
+    hidden_proto(setfilecon_raw)
+    hidden_proto(lsetfilecon_raw)
+    hidden_proto(fsetfilecon_raw)
+    hidden_proto(setexeccon)
+    hidden_proto(setexeccon_raw)
+    hidden_proto(getfscreatecon_raw)
+    hidden_proto(getkeycreatecon_raw)
+    hidden_proto(getsockcreatecon_raw)
+    hidden_proto(setfscreatecon_raw)
+    hidden_proto(setkeycreatecon_raw)
+    hidden_proto(setsockcreatecon_raw)
+    hidden_proto(security_getenforce)
+    hidden_proto(security_setenforce)
+    hidden_proto(security_deny_unknown)
+    hidden_proto(selinux_binary_policy_path)
+    hidden_proto(selinux_default_context_path)
+    hidden_proto(selinux_securetty_types_path)
+    hidden_proto(selinux_failsafe_context_path)
+    hidden_proto(selinux_removable_context_path)
+    hidden_proto(selinux_virtual_domain_context_path)
+    hidden_proto(selinux_virtual_image_context_path)
+    hidden_proto(selinux_file_context_path)
+    hidden_proto(selinux_file_context_homedir_path)
+    hidden_proto(selinux_file_context_local_path)
+    hidden_proto(selinux_file_context_subs_path)
+    hidden_proto(selinux_netfilter_context_path)
+    hidden_proto(selinux_homedir_context_path)
+    hidden_proto(selinux_user_contexts_path)
+    hidden_proto(selinux_booleans_path)
+    hidden_proto(selinux_customizable_types_path)
+    hidden_proto(selinux_media_context_path)
+    hidden_proto(selinux_x_context_path)
+    hidden_proto(selinux_sepgsql_context_path)
+    hidden_proto(selinux_path)
+    hidden_proto(selinux_check_passwd_access)
+    hidden_proto(selinux_check_securetty_context)
+    hidden_proto(matchpathcon_init_prefix)
+    hidden_proto(selinux_users_path)
+    hidden_proto(selinux_usersconf_path);
+hidden_proto(selinux_translations_path);
+hidden_proto(selinux_colors_path);
+hidden_proto(selinux_getenforcemode);
+hidden_proto(selinux_getpolicytype);
+hidden_proto(selinux_raw_to_trans_context);
+hidden_proto(selinux_trans_to_raw_context);
+    hidden_proto(selinux_raw_context_to_color);
+hidden_proto(security_get_initial_context);
+hidden_proto(security_get_initial_context_raw);
+hidden_proto(selinux_reset_config);
+
+extern int selinux_page_size hidden;
+
+/* Make pthread_once optional */
+#pragma weak pthread_once
+#pragma weak pthread_key_create
+#pragma weak pthread_key_delete
+#pragma weak pthread_setspecific
+
+/* Call handler iff the first call.  */
+#define __selinux_once(ONCE_CONTROL, INIT_FUNCTION)	\
+	do {						\
+		if (pthread_once != NULL)		\
+			pthread_once (&(ONCE_CONTROL), (INIT_FUNCTION));  \
+		else if ((ONCE_CONTROL) == PTHREAD_ONCE_INIT) {		  \
+			INIT_FUNCTION ();		\
+			(ONCE_CONTROL) = 2;		\
+		}					\
+	} while (0)
+
+/* Pthread key macros */
+#define __selinux_key_create(KEY, DESTRUCTOR)			\
+	do {							\
+		if (pthread_key_create != NULL)			\
+			pthread_key_create(KEY, DESTRUCTOR);	\
+	} while (0)
+
+#define __selinux_key_delete(KEY)				\
+	do {							\
+		if (pthread_key_delete != NULL)			\
+			pthread_key_delete(KEY);		\
+	} while (0)
+
+#define __selinux_setspecific(KEY, VALUE)			\
+	do {							\
+		if (pthread_setspecific != NULL)		\
+			pthread_setspecific(KEY, VALUE);	\
+	} while (0)
+
+
diff --git a/distrib/libselinux/src/selinux_netlink.h b/distrib/libselinux/src/selinux_netlink.h
new file mode 100644
index 0000000..88ef551
--- /dev/null
+++ b/distrib/libselinux/src/selinux_netlink.h
@@ -0,0 +1,31 @@
+/*
+ * Netlink event notifications for SELinux.
+ *
+ * Author: James Morris <jmorris@redhat.com>
+ */
+#ifndef _LINUX_SELINUX_NETLINK_H
+#define _LINUX_SELINUX_NETLINK_H
+
+/* Message types. */
+#define SELNL_MSG_BASE 0x10
+enum {
+	SELNL_MSG_SETENFORCE = SELNL_MSG_BASE,
+	SELNL_MSG_POLICYLOAD,
+	SELNL_MSG_MAX
+};
+
+/* Multicast groups */
+#define SELNL_GRP_NONE		0x00000000
+#define SELNL_GRP_AVC		0x00000001	/* AVC notifications */
+#define SELNL_GRP_ALL		0xffffffff
+
+/* Message structures */
+struct selnl_msg_setenforce {
+	int32_t val;
+};
+
+struct selnl_msg_policyload {
+	uint32_t seqno;
+};
+
+#endif				/* _LINUX_SELINUX_NETLINK_H */
diff --git a/distrib/libselinux/src/sestatus.c b/distrib/libselinux/src/sestatus.c
new file mode 100644
index 0000000..ed29dc5
--- /dev/null
+++ b/distrib/libselinux/src/sestatus.c
@@ -0,0 +1,349 @@
+/*
+ * sestatus.c
+ *
+ * APIs to reference SELinux kernel status page (/selinux/status)
+ *
+ * Author: KaiGai Kohei <kaigai@ak.jp.nec.com>
+ *
+ */
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "avc_internal.h"
+#include "policy.h"
+
+/*
+ * copied from the selinux/include/security.h
+ */
+struct selinux_status_t
+{
+	uint32_t	version;	/* version number of thie structure */
+	uint32_t	sequence;	/* sequence number of seqlock logic */
+	uint32_t	enforcing;	/* current setting of enforcing mode */
+	uint32_t	policyload;	/* times of policy reloaded */
+	uint32_t	deny_unknown;	/* current setting of deny_unknown */
+	/* version > 0 support above status */
+} __attribute((packed));
+
+/*
+ * `selinux_status'
+ *
+ * NULL : not initialized yet
+ * MAP_FAILED : opened, but fallback-mode
+ * Valid Pointer : opened and mapped correctly
+ */
+static struct selinux_status_t *selinux_status = NULL;
+static int			selinux_status_fd;
+static uint32_t			last_seqno;
+
+static uint32_t			fallback_sequence;
+static int			fallback_enforcing;
+static int			fallback_policyload;
+
+/*
+ * read_sequence
+ *
+ * A utility routine to reference kernel status page according to
+ * seqlock logic. Since selinux_status->sequence is an odd value during
+ * the kernel status page being updated, we try to synchronize completion
+ * of this updating, but we assume it is rare.
+ * The sequence is almost even number.
+ *
+ * __sync_synchronize is a portable memory barrier for various kind
+ * of architecture that is supported by GCC.
+ */
+static inline uint32_t read_sequence(struct selinux_status_t *status)
+{
+	uint32_t	seqno = 0;
+
+	do {
+		/*
+		 * No need for sched_yield() in the first trial of
+		 * this loop.
+		 */
+		if (seqno & 0x0001)
+			sched_yield();
+
+		seqno = status->sequence;
+
+		__sync_synchronize();
+
+	} while (seqno & 0x0001);
+
+	return seqno;
+}
+
+/*
+ * selinux_status_updated
+ *
+ * It returns whether something has been happened since the last call.
+ * Because `selinux_status->sequence' shall be always incremented on
+ * both of setenforce/policyreload events, so differences from the last
+ * value informs us something has been happened.
+ */
+int selinux_status_updated(void)
+{
+	uint32_t	curr_seqno;
+	int		result = 0;
+
+	if (selinux_status == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (selinux_status == MAP_FAILED) {
+		if (avc_netlink_check_nb() < 0)
+			return -1;
+
+		curr_seqno = fallback_sequence;
+	} else {
+		curr_seqno = read_sequence(selinux_status);
+	}
+
+	/*
+	 * `curr_seqno' is always even-number, so it does not match with
+	 * `last_seqno' being initialized to odd-number in the first call.
+	 * We never return 'something was updated' in the first call,
+	 * because this function focuses on status-updating since the last
+	 * invocation.
+	 */
+	if (last_seqno & 0x0001)
+		last_seqno = curr_seqno;
+
+	if (last_seqno != curr_seqno)
+	{
+		last_seqno = curr_seqno;
+		result = 1;
+	}
+	return result;
+}
+
+/*
+ * selinux_status_getenforce
+ *
+ * It returns the current performing mode of SELinux.
+ * 1 means currently we run in enforcing mode, or 0 means permissive mode.
+ */
+int selinux_status_getenforce(void)
+{
+	uint32_t	seqno;
+	uint32_t	enforcing;
+
+	if (selinux_status == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (selinux_status == MAP_FAILED) {
+		if (avc_netlink_check_nb() < 0)
+			return -1;
+
+		return fallback_enforcing;
+	}
+
+	/* sequence must not be changed during references */
+	do {
+		seqno = read_sequence(selinux_status);
+
+		enforcing = selinux_status->enforcing;
+
+	} while (seqno != read_sequence(selinux_status));
+
+	return enforcing ? 1 : 0;
+}
+
+/*
+ * selinux_status_policyload
+ *
+ * It returns times of policy reloaded on the running system.
+ * Note that it is not a reliable value on fallback-mode until it receives
+ * the first event message via netlink socket, so, a correct usage of this
+ * value is to compare it with the previous value to detect policy reloaded
+ * event.
+ */
+int selinux_status_policyload(void)
+{
+	uint32_t	seqno;
+	uint32_t	policyload;
+
+	if (selinux_status == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (selinux_status == MAP_FAILED) {
+		if (avc_netlink_check_nb() < 0)
+			return -1;
+
+		return fallback_policyload;
+	}
+
+	/* sequence must not be changed during references */
+	do {
+		seqno = read_sequence(selinux_status);
+
+		policyload = selinux_status->policyload;
+
+	} while (seqno != read_sequence(selinux_status));
+
+	return policyload;
+}
+
+/*
+ * selinux_status_deny_unknown
+ *
+ * It returns a guideline to handle undefined object classes or permissions.
+ * 0 means SELinux treats policy queries on undefined stuff being allowed,
+ * however, 1 means such queries are denied.
+ */
+int selinux_status_deny_unknown(void)
+{
+	uint32_t	seqno;
+	uint32_t	deny_unknown;
+
+	if (selinux_status == NULL) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (selinux_status == MAP_FAILED)
+		return security_deny_unknown();
+
+	/* sequence must not be changed during references */
+	do {
+		seqno = read_sequence(selinux_status);
+
+		deny_unknown = selinux_status->deny_unknown;
+
+	} while (seqno != read_sequence(selinux_status));
+
+	return deny_unknown ? 1 : 0;
+}
+
+/*
+ * callback routines for fallback case using netlink socket
+ */
+static int fallback_cb_setenforce(int enforcing)
+{
+	fallback_sequence += 2;
+	fallback_enforcing = enforcing;
+
+	return 0;
+}
+
+static int fallback_cb_policyload(int policyload)
+{
+	fallback_sequence += 2;
+	fallback_policyload = policyload;
+
+	return 0;
+}
+
+/*
+ * selinux_status_open
+ *
+ * It tries to open and mmap kernel status page (/selinux/status).
+ * Since Linux 2.6.37 or later supports this feature, we may run
+ * fallback routine using a netlink socket on older kernels, if
+ * the supplied `fallback' is not zero.
+ * It returns 0 on success, or -1 on error.
+ */
+int selinux_status_open(int fallback)
+{
+	int	fd;
+	char	path[PATH_MAX];
+	long	pagesize;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	pagesize = sysconf(_SC_PAGESIZE);
+	if (pagesize < 0)
+		return -1;
+
+	snprintf(path, sizeof(path), "%s/status", selinux_mnt);
+	fd = open(path, O_RDONLY | O_CLOEXEC);
+	if (fd < 0)
+		goto error;
+
+	selinux_status = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0);
+	if (selinux_status == MAP_FAILED) {
+		close(fd);
+		goto error;
+	}
+	selinux_status_fd = fd;
+	last_seqno = (uint32_t)(-1);
+
+	return 0;
+
+error:
+	/*
+	 * If caller wants fallback routine, we try to provide
+	 * an equivalent functionality using existing netlink
+	 * socket, although it needs system call invocation to
+	 * receive event notification.
+	 */
+	if (fallback && avc_netlink_open(0) == 0) {
+		union selinux_callback	cb;
+
+		/* register my callbacks */
+		cb.func_setenforce = fallback_cb_setenforce;
+		selinux_set_callback(SELINUX_CB_SETENFORCE, cb);
+		cb.func_policyload = fallback_cb_policyload;
+		selinux_set_callback(SELINUX_CB_POLICYLOAD, cb);
+
+		/* mark as fallback mode */
+		selinux_status = MAP_FAILED;
+		selinux_status_fd = avc_netlink_acquire_fd();
+		last_seqno = (uint32_t)(-1);
+
+		fallback_sequence = 0;
+		fallback_enforcing = security_getenforce();
+		fallback_policyload = 0;
+
+		return 1;
+	}
+	selinux_status = NULL;
+
+	return -1;
+}
+
+/*
+ * selinux_status_close
+ *
+ * It unmap and close the kernel status page, or close netlink socket
+ * if fallback mode.
+ */
+void selinux_status_close(void)
+{
+	long pagesize;
+
+	/* not opened */
+	if (selinux_status == NULL)
+		return;
+
+	/* fallback-mode */
+	if (selinux_status == MAP_FAILED)
+	{
+		avc_netlink_release_fd();
+		avc_netlink_close();
+		selinux_status = NULL;
+		return;
+	}
+
+	pagesize = sysconf(_SC_PAGESIZE);
+	/* not much we can do other than leak memory */
+	if (pagesize > 0)
+		munmap(selinux_status, pagesize);
+	selinux_status = NULL;
+
+	close(selinux_status_fd);
+	selinux_status_fd = -1;
+	last_seqno = (uint32_t)(-1);
+}
diff --git a/distrib/libselinux/src/setenforce.c b/distrib/libselinux/src/setenforce.c
new file mode 100644
index 0000000..e5e7612
--- /dev/null
+++ b/distrib/libselinux/src/setenforce.c
@@ -0,0 +1,37 @@
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include <stdio.h>
+#include <limits.h>
+
+int security_setenforce(int value)
+{
+	int fd, ret;
+	char path[PATH_MAX];
+	char buf[20];
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return -1;
+	}
+
+	snprintf(path, sizeof path, "%s/enforce", selinux_mnt);
+	fd = open(path, O_RDWR);
+	if (fd < 0)
+		return -1;
+
+	snprintf(buf, sizeof buf, "%d", value);
+	ret = write(fd, buf, strlen(buf));
+	close(fd);
+	if (ret < 0)
+		return -1;
+
+	return 0;
+}
+
+hidden_def(security_setenforce)
diff --git a/distrib/libselinux/src/setfilecon.c b/distrib/libselinux/src/setfilecon.c
new file mode 100644
index 0000000..81322f8
--- /dev/null
+++ b/distrib/libselinux/src/setfilecon.c
@@ -0,0 +1,15 @@
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/xattr.h>
+#include "selinux_internal.h"
+#include "policy.h"
+
+int setfilecon(const char *path, const char *context)
+{
+	return setxattr(path, XATTR_NAME_SELINUX, context, strlen(context) + 1,
+			0);
+}
+
diff --git a/distrib/libselinux/src/stringrep.c b/distrib/libselinux/src/stringrep.c
new file mode 100644
index 0000000..5b63673
--- /dev/null
+++ b/distrib/libselinux/src/stringrep.c
@@ -0,0 +1,297 @@
+/*
+ * String representation support for classes and permissions.
+ */
+#include <sys/stat.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <ctype.h>
+#include "selinux_internal.h"
+#include "policy.h"
+#include "mapping.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+#define MAXVECTORS 8*sizeof(access_vector_t)
+
+static pthread_once_t once = PTHREAD_ONCE_INIT;
+
+struct discover_class_node {
+	char *name;
+	security_class_t value;
+	char **perms;
+
+	struct discover_class_node *next;
+};
+
+static struct discover_class_node *discover_class_cache = NULL;
+
+static struct discover_class_node * get_class_cache_entry_name(const char *s)
+{
+	struct discover_class_node *node = discover_class_cache;
+
+	for (; node != NULL && strcmp(s,node->name) != 0; node = node->next);
+
+	return node;
+}
+
+static struct discover_class_node * get_class_cache_entry_value(security_class_t c)
+{
+	struct discover_class_node *node = discover_class_cache;
+
+	for (; node != NULL && c != node->value; node = node->next);
+
+	return node;
+}
+
+static struct discover_class_node * discover_class(const char *s)
+{
+	int fd, ret;
+	char path[PATH_MAX];
+	char buf[20];
+	DIR *dir;
+	struct dirent *dentry;
+	size_t i;
+
+	struct discover_class_node *node;
+
+	if (!selinux_mnt) {
+		errno = ENOENT;
+		return NULL;
+	}
+
+	/* allocate a node */
+	node = malloc(sizeof(struct discover_class_node));
+	if (node == NULL)
+		return NULL;
+
+	/* allocate array for perms */
+	node->perms = calloc(MAXVECTORS,sizeof(char*));
+	if (node->perms == NULL)
+		goto err1;
+
+	/* load up the name */
+	node->name = strdup(s);
+	if (node->name == NULL)
+		goto err2;
+
+	/* load up class index */
+	snprintf(path, sizeof path, "%s/class/%s/index", selinux_mnt,s);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		goto err3;
+
+	memset(buf, 0, sizeof(buf));
+	ret = read(fd, buf, sizeof(buf) - 1);
+	close(fd);
+	if (ret < 0)
+		goto err3;
+
+	if (sscanf(buf, "%hu", &node->value) != 1)
+		goto err3;
+
+	/* load up permission indicies */
+	snprintf(path, sizeof path, "%s/class/%s/perms",selinux_mnt,s);
+	dir = opendir(path);
+	if (dir == NULL)
+		goto err3;
+
+	dentry = readdir(dir);
+	while (dentry != NULL) {
+		unsigned int value;
+		struct stat m;
+
+		snprintf(path, sizeof path, "%s/class/%s/perms/%s", selinux_mnt,s,dentry->d_name);
+		if (stat(path,&m) < 0)
+			goto err4;
+
+		if (m.st_mode & S_IFDIR) {
+			dentry = readdir(dir);
+			continue;
+		}
+
+		fd = open(path, O_RDONLY);
+		if (fd < 0)
+			goto err4;
+
+		memset(buf, 0, sizeof(buf));
+		ret = read(fd, buf, sizeof(buf) - 1);
+		close(fd);
+		if (ret < 0)
+			goto err4;
+
+		if (sscanf(buf, "%u", &value) != 1)
+			goto err4;
+
+		node->perms[value-1] = strdup(dentry->d_name);
+		if (node->perms[value-1] == NULL)
+			goto err4;
+
+		dentry = readdir(dir);
+	}
+	closedir(dir);
+
+	node->next = discover_class_cache;
+	discover_class_cache = node;
+
+	return node;
+
+err4:
+	closedir(dir);
+	for (i=0; i<MAXVECTORS; i++)
+		free(node->perms[i]);
+err3:
+	free(node->name);
+err2:
+	free(node->perms);
+err1:
+	free(node);
+	return NULL;
+}
+
+void flush_class_cache(void)
+{
+	struct discover_class_node *cur = discover_class_cache, *prev = NULL;
+	size_t i;
+
+	while (cur != NULL) {
+		free(cur->name);
+
+		for (i=0 ; i<MAXVECTORS ; i++)
+			free(cur->perms[i]);
+
+		free(cur->perms);
+
+		prev = cur;
+		cur = cur->next;
+
+		free(prev);
+	}
+
+	discover_class_cache = NULL;
+}
+
+security_class_t string_to_security_class(const char *s)
+{
+	struct discover_class_node *node;
+
+	node = get_class_cache_entry_name(s);
+	if (node == NULL) {
+		node = discover_class(s);
+
+		if (node == NULL) {
+			errno = EINVAL;
+			return 0;
+		}
+	}
+
+	return map_class(node->value);
+}
+
+access_vector_t string_to_av_perm(security_class_t tclass, const char *s)
+{
+	struct discover_class_node *node;
+	security_class_t kclass = unmap_class(tclass);
+
+	node = get_class_cache_entry_value(kclass);
+	if (node != NULL) {
+		size_t i;
+		for (i=0; i<MAXVECTORS && node->perms[i] != NULL; i++)
+			if (strcmp(node->perms[i],s) == 0)
+				return map_perm(tclass, 1<<i);
+	}
+
+	errno = EINVAL;
+	return 0;
+}
+
+const char *security_class_to_string(security_class_t tclass)
+{
+	struct discover_class_node *node;
+
+	tclass = unmap_class(tclass);
+
+	node = get_class_cache_entry_value(tclass);
+	if (node)
+		return node->name;
+	return NULL;
+}
+
+const char *security_av_perm_to_string(security_class_t tclass,
+				       access_vector_t av)
+{
+	struct discover_class_node *node;
+	size_t i;
+
+	av = unmap_perm(tclass, av);
+	tclass = unmap_class(tclass);
+
+	node = get_class_cache_entry_value(tclass);
+	if (av && node)
+		for (i = 0; i<MAXVECTORS; i++)
+			if ((1<<i) & av)
+				return node->perms[i];
+
+	return NULL;
+}
+
+int security_av_string(security_class_t tclass, access_vector_t av, char **res)
+{
+	unsigned int i = 0;
+	size_t len = 5;
+	access_vector_t tmp = av;
+	int rc = 0;
+	const char *str;
+	char *ptr;
+
+	/* first pass computes the required length */
+	while (tmp) {
+		if (tmp & 1) {
+			str = security_av_perm_to_string(tclass, av & (1<<i));
+			if (str)
+				len += strlen(str) + 1;
+			else {
+				rc = -1;
+				errno = EINVAL;
+				goto out;
+			}
+		}
+		tmp >>= 1;
+		i++;
+	}
+
+	*res = malloc(len);
+	if (!*res) {
+		rc = -1;
+		goto out;
+	}
+
+	/* second pass constructs the string */
+	i = 0;
+	tmp = av;
+	ptr = *res;
+
+	if (!av) {
+		sprintf(ptr, "null");
+		goto out;
+	}
+
+	ptr += sprintf(ptr, "{ ");
+	while (tmp) {
+		if (tmp & 1)
+			ptr += sprintf(ptr, "%s ", security_av_perm_to_string(
+					       tclass, av & (1<<i)));
+		tmp >>= 1;
+		i++;
+	}
+	sprintf(ptr, "}");
+out:
+	return rc;
+}
diff --git a/distrib/libsparse/README b/distrib/libsparse/README
new file mode 100644
index 0000000..6ecba7b
--- /dev/null
+++ b/distrib/libsparse/README
@@ -0,0 +1,6 @@
+This directory contains a copy of the sources of the AOSP libsparse library.
+
+For reference, the files were taken from $AOSP/system/core/libsparse with
+the following commit:
+
+               252b0e2b46e3d5e71a8b5c55928dc9ca62811f0a
diff --git a/distrib/libsparse/include/sparse/sparse.h b/distrib/libsparse/include/sparse/sparse.h
new file mode 100644
index 0000000..8b757d2
--- /dev/null
+++ b/distrib/libsparse/include/sparse/sparse.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2012 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 _LIBSPARSE_SPARSE_H_
+#define _LIBSPARSE_SPARSE_H_
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+struct sparse_file;
+
+/**
+ * sparse_file_new - create a new sparse file cookie
+ *
+ * @block_size - minimum size of a chunk
+ * @len - size of the expanded sparse file.
+ *
+ * Creates a new sparse_file cookie that can be used to associate data
+ * blocks.  Can later be written to a file with a variety of options.
+ * block_size specifies the minimum size of a chunk in the file.  The maximum
+ * size of the file is 2**32 * block_size (16TB for 4k block size).
+ *
+ * Returns the sparse file cookie, or NULL on error.
+ */
+struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len);
+
+/**
+ * sparse_file_destroy - destroy a sparse file cookie
+ *
+ * @s - sparse file cookie
+ *
+ * Destroys a sparse file cookie.  After destroy, all memory passed in to
+ * sparse_file_add_data can be freed by the caller
+ */
+void sparse_file_destroy(struct sparse_file *s);
+
+/**
+ * sparse_file_add_data - associate a data chunk with a sparse file
+ *
+ * @s - sparse file cookie
+ * @data - pointer to data block
+ * @len - length of the data block
+ * @block - offset in blocks into the sparse file to place the data chunk
+ *
+ * Associates a data chunk with a sparse file cookie.  The region
+ * [block * block_size : block * block_size + len) must not already be used in
+ * the sparse file. If len is not a multiple of the block size the data
+ * will be padded with zeros.
+ *
+ * The data pointer must remain valid until the sparse file is closed or the
+ * data block is removed from the sparse file.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_data(struct sparse_file *s,
+		void *data, unsigned int len, unsigned int block);
+
+/**
+ * sparse_file_add_fill - associate a fill chunk with a sparse file
+ *
+ * @s - sparse file cookie
+ * @fill_val - 32 bit fill data
+ * @len - length of the fill block
+ * @block - offset in blocks into the sparse file to place the fill chunk
+ *
+ * Associates a chunk filled with fill_val with a sparse file cookie.
+ * The region [block * block_size : block * block_size + len) must not already
+ * be used in the sparse file. If len is not a multiple of the block size the
+ * data will be padded with zeros.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_fill(struct sparse_file *s,
+		uint32_t fill_val, unsigned int len, unsigned int block);
+
+/**
+ * sparse_file_add_file - associate a chunk of a file with a sparse file
+ *
+ * @s - sparse file cookie
+ * @filename - filename of the file to be copied
+ * @file_offset - offset into the copied file
+ * @len - length of the copied block
+ * @block - offset in blocks into the sparse file to place the file chunk
+ *
+ * Associates a chunk of an existing file with a sparse file cookie.
+ * The region [block * block_size : block * block_size + len) must not already
+ * be used in the sparse file. If len is not a multiple of the block size the
+ * data will be padded with zeros.
+ *
+ * Allows adding large amounts of data to a sparse file without needing to keep
+ * it all mapped.  File size is limited by available virtual address space,
+ * exceptionally large files may need to be added in multiple chunks.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_file(struct sparse_file *s,
+		const char *filename, int64_t file_offset, unsigned int len,
+		unsigned int block);
+
+/**
+ * sparse_file_add_file - associate a chunk of a file with a sparse file
+ *
+ * @s - sparse file cookie
+ * @filename - filename of the file to be copied
+ * @file_offset - offset into the copied file
+ * @len - length of the copied block
+ * @block - offset in blocks into the sparse file to place the file chunk
+ *
+ * Associates a chunk of an existing fd with a sparse file cookie.
+ * The region [block * block_size : block * block_size + len) must not already
+ * be used in the sparse file. If len is not a multiple of the block size the
+ * data will be padded with zeros.
+ *
+ * Allows adding large amounts of data to a sparse file without needing to keep
+ * it all mapped.  File size is limited by available virtual address space,
+ * exceptionally large files may need to be added in multiple chunks.
+ *
+ * The fd must remain open until the sparse file is closed or the fd block is
+ * removed from the sparse file.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_add_fd(struct sparse_file *s,
+		int fd, int64_t file_offset, unsigned int len, unsigned int block);
+
+/**
+ * sparse_file_write - write a sparse file to a file
+ *
+ * @s - sparse file cookie
+ * @fd - file descriptor to write to
+ * @gz - write a gzipped file
+ * @sparse - write in the Android sparse file format
+ * @crc - append a crc chunk
+ *
+ * Writes a sparse file to a file.  If gz is true, the data will be passed
+ * through zlib.  If sparse is true, the file will be written in the Android
+ * sparse file format.  If sparse is false, the file will be written by seeking
+ * over unused chunks, producing a smaller file if the filesystem supports
+ * sparse files.  If crc is true, the crc of the expanded data will be
+ * calculated and appended in a crc chunk.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
+		bool crc);
+
+/**
+ * sparse_file_len - return the length of a sparse file if written to disk
+ *
+ * @s - sparse file cookie
+ * @sparse - write in the Android sparse file format
+ * @crc - append a crc chunk
+ *
+ * Returns the size a sparse file would be on disk if it were written in the
+ * specified format.  If sparse is true, this is the size of the data in the
+ * sparse format.  If sparse is false, this is the size of the normal
+ * non-sparse file.
+ */
+int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc);
+
+/**
+ * sparse_file_callback - call a callback for blocks in sparse file
+ *
+ * @s - sparse file cookie
+ * @sparse - write in the Android sparse file format
+ * @crc - append a crc chunk
+ * @write - function to call for each block
+ * @priv - value that will be passed as the first argument to write
+ *
+ * Writes a sparse file by calling a callback function.  If sparse is true, the
+ * file will be written in the Android sparse file format.  If crc is true, the
+ * crc of the expanded data will be calculated and appended in a crc chunk.
+ * The callback 'write' will be called with data and length for each data,
+ * and with data==NULL to skip over a region (only used for non-sparse format).
+ * The callback should return negative on error, 0 on success.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
+		int (*write)(void *priv, const void *data, int len), void *priv);
+
+/**
+ * sparse_file_read - read a file into a sparse file cookie
+ *
+ * @s - sparse file cookie
+ * @fd - file descriptor to read from
+ * @sparse - read a file in the Android sparse file format
+ * @crc - verify the crc of a file in the Android sparse file format
+ *
+ * Reads a file into a sparse file cookie.  If sparse is true, the file is
+ * assumed to be in the Android sparse file format.  If sparse is false, the
+ * file will be sparsed by looking for block aligned chunks of all zeros or
+ * another 32 bit value.  If crc is true, the crc of the sparse file will be
+ * verified.
+ *
+ * Returns 0 on success, negative errno on error.
+ */
+int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc);
+
+/**
+ * sparse_file_import - import an existing sparse file
+ *
+ * @s - sparse file cookie
+ * @verbose - print verbose errors while reading the sparse file
+ * @crc - verify the crc of a file in the Android sparse file format
+ *
+ * Reads an existing sparse file into a sparse file cookie, recreating the same
+ * sparse cookie that was used to write it.  If verbose is true, prints verbose
+ * errors when the sparse file is formatted incorrectly.
+ *
+ * Returns a new sparse file cookie on success, NULL on error.
+ */
+struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc);
+
+/**
+ * sparse_file_import_auto - import an existing sparse or normal file
+ *
+ * @fd - file descriptor to read from
+ * @crc - verify the crc of a file in the Android sparse file format
+ *
+ * Reads an existing sparse or normal file into a sparse file cookie.
+ * Attempts to determine if the file is sparse or not by looking for the sparse
+ * file magic number in the first 4 bytes.  If the file is not sparse, the file
+ * will be sparsed by looking for block aligned chunks of all zeros or another
+ * 32 bit value.  If crc is true, the crc of the sparse file will be verified.
+ *
+ * Returns a new sparse file cookie on success, NULL on error.
+ */
+struct sparse_file *sparse_file_import_auto(int fd, bool crc);
+
+/** sparse_file_resparse - rechunk an existing sparse file into smaller files
+ *
+ * @in_s - sparse file cookie of the existing sparse file
+ * @max_len - maximum file size
+ * @out_s - array of sparse file cookies
+ * @out_s_count - size of out_s array
+ *
+ * Splits chunks of an existing sparse file into smaller sparse files such that
+ * each sparse file is less than max_len.  Returns the number of sparse_files
+ * that would have been written to out_s if out_s were big enough.
+ */
+int sparse_file_resparse(struct sparse_file *in_s, unsigned int max_len,
+		struct sparse_file **out_s, int out_s_count);
+
+/**
+ * sparse_file_verbose - set a sparse file cookie to print verbose errors
+ *
+ * @s - sparse file cookie
+ *
+ * Print verbose sparse file errors whenever using the sparse file cookie.
+ */
+void sparse_file_verbose(struct sparse_file *s);
+
+/**
+ * sparse_print_verbose - function called to print verbose errors
+ *
+ * By default, verbose errors will print to standard error.
+ * sparse_print_verbose may be overridden to log verbose errors somewhere else.
+ *
+ */
+extern void (*sparse_print_verbose)(const char *fmt, ...);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif
diff --git a/distrib/libsparse/sources.mk b/distrib/libsparse/sources.mk
new file mode 100644
index 0000000..d76f7bd
--- /dev/null
+++ b/distrib/libsparse/sources.mk
@@ -0,0 +1,58 @@
+# Build file for libsparse and associated executables.
+
+# Update LOCAL_PATH after saving old value.
+LIBSPARSE_OLD_LOCAL_PATH := $(LOCAL_PATH)
+LOCAL_PATH := $(call my-dir)
+
+LIBSPARSE_SOURCES := \
+    src/backed_block.c \
+    src/output_file.c \
+    src/sparse.c \
+    src/sparse_crc32.c \
+    src/sparse_err.c \
+    src/sparse_read.c \
+
+LIBSPARSE_INCLUDES := $(LOCAL_PATH)/include $(ZLIB_INCLUDES)
+
+ifeq (windows,$(HOST_OS))
+LIBSPARSE_CFLAGS := -DUSE_MINGW=1
+endif
+
+$(call start-emulator-library,emulator-libsparse)
+LOCAL_SRC_FILES := $(LIBSPARSE_SOURCES)
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES) $(LOCAL_PATH)/src
+LOCAL_CFLAGS := $(LIBSPARSE_CFLAGS)
+$(call end-emulator-library)
+
+$(call start-emulator64-library,emulator64-libsparse)
+LOCAL_SRC_FILES := $(LIBSPARSE_SOURCES)
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES) $(LOCAL_PATH)/src
+LOCAL_CFLAGS := $(LIBSPARSE_CFLAGS)
+$(call end-emulator-library)
+
+$(call start-emulator-program,emulator_img2simg)
+LOCAL_SRC_FILES := src/img2simg.c
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES)
+LOCAL_STATIC_LIBRARIES := emulator-libsparse emulator-zlib
+$(call end-emulator-program)
+
+$(call start-emulator-program,emulator_simg2img)
+LOCAL_SRC_FILES := src/simg2img.c
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES)
+LOCAL_STATIC_LIBRARIES := emulator-libsparse emulator-zlib
+$(call end-emulator-program)
+
+$(call start-emulator64-program,emulator64_img2simg)
+LOCAL_SRC_FILES := src/img2simg.c
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES)
+LOCAL_STATIC_LIBRARIES := emulator64-libsparse emulator64-zlib
+#$(call end-emulator-program)
+
+$(call start-emulator64-program,emulator64_simg2img)
+LOCAL_SRC_FILES := src/simg2img.c
+LOCAL_C_INCLUDES := $(LIBSPARSE_INCLUDES)
+LOCAL_STATIC_LIBRARIES := emulator64-libsparse emulator64-zlib
+#$(call end-emulator-program)
+
+# Reset LOCAL_PATH before exiting this build file.
+LOCAL_PATH := $(LIBSPARSE_OLD_LOCAL_PATH)
diff --git a/distrib/libsparse/src/backed_block.c b/distrib/libsparse/src/backed_block.c
new file mode 100644
index 0000000..3e72b57
--- /dev/null
+++ b/distrib/libsparse/src/backed_block.c
@@ -0,0 +1,400 @@
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "backed_block.h"
+#include "sparse_defs.h"
+
+struct backed_block {
+	unsigned int block;
+	unsigned int len;
+	enum backed_block_type type;
+	union {
+		struct {
+			void *data;
+		} data;
+		struct {
+			char *filename;
+			int64_t offset;
+		} file;
+		struct {
+			int fd;
+			int64_t offset;
+		} fd;
+		struct {
+			uint32_t val;
+		} fill;
+	};
+	struct backed_block *next;
+};
+
+struct backed_block_list {
+	struct backed_block *data_blocks;
+	struct backed_block *last_used;
+	unsigned int block_size;
+};
+
+struct backed_block *backed_block_iter_new(struct backed_block_list *bbl)
+{
+	return bbl->data_blocks;
+}
+
+struct backed_block *backed_block_iter_next(struct backed_block *bb)
+{
+	return bb->next;
+}
+
+unsigned int backed_block_len(struct backed_block *bb)
+{
+	return bb->len;
+}
+
+unsigned int backed_block_block(struct backed_block *bb)
+{
+	return bb->block;
+}
+
+void *backed_block_data(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_DATA);
+	return bb->data.data;
+}
+
+const char *backed_block_filename(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_FILE);
+	return bb->file.filename;
+}
+
+int backed_block_fd(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_FD);
+	return bb->fd.fd;
+}
+
+int64_t backed_block_file_offset(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_FILE || bb->type == BACKED_BLOCK_FD);
+	if (bb->type == BACKED_BLOCK_FILE) {
+		return bb->file.offset;
+	} else { /* bb->type == BACKED_BLOCK_FD */
+		return bb->fd.offset;
+	}
+}
+
+uint32_t backed_block_fill_val(struct backed_block *bb)
+{
+	assert(bb->type == BACKED_BLOCK_FILL);
+	return bb->fill.val;
+}
+
+enum backed_block_type backed_block_type(struct backed_block *bb)
+{
+	return bb->type;
+}
+
+void backed_block_destroy(struct backed_block *bb)
+{
+	if (bb->type == BACKED_BLOCK_FILE) {
+		free(bb->file.filename);
+	}
+
+	free(bb);
+}
+
+struct backed_block_list *backed_block_list_new(unsigned int block_size)
+{
+	struct backed_block_list *b = calloc(sizeof(struct backed_block_list), 1);
+	b->block_size = block_size;
+	return b;
+}
+
+void backed_block_list_destroy(struct backed_block_list *bbl)
+{
+	if (bbl->data_blocks) {
+		struct backed_block *bb = bbl->data_blocks;
+		while (bb) {
+			struct backed_block *next = bb->next;
+			backed_block_destroy(bb);
+			bb = next;
+		}
+	}
+
+	free(bbl);
+}
+
+void backed_block_list_move(struct backed_block_list *from,
+		struct backed_block_list *to, struct backed_block *start,
+		struct backed_block *end)
+{
+	struct backed_block *bb;
+
+	if (start == NULL) {
+		start = from->data_blocks;
+	}
+
+	if (!end) {
+		for (end = start; end && end->next; end = end->next)
+			;
+	}
+
+	if (start == NULL || end == NULL) {
+		return;
+	}
+
+	from->last_used = NULL;
+	to->last_used = NULL;
+	if (from->data_blocks == start) {
+		from->data_blocks = end->next;
+	} else {
+		for (bb = from->data_blocks; bb; bb = bb->next) {
+			if (bb->next == start) {
+				bb->next = end->next;
+				break;
+			}
+		}
+	}
+
+	if (!to->data_blocks) {
+		to->data_blocks = start;
+		end->next = NULL;
+	} else {
+		for (bb = to->data_blocks; bb; bb = bb->next) {
+			if (!bb->next || bb->next->block > start->block) {
+				end->next = bb->next;
+				bb->next = start;
+				break;
+			}
+		}
+	}
+}
+
+/* may free b */
+static int merge_bb(struct backed_block_list *bbl,
+		struct backed_block *a, struct backed_block *b)
+{
+	unsigned int block_len;
+
+	/* Block doesn't exist (possible if one block is the last block) */
+	if (!a || !b) {
+		return -EINVAL;
+	}
+
+	assert(a->block < b->block);
+
+	/* Blocks are of different types */
+	if (a->type != b->type) {
+		return -EINVAL;
+	}
+
+	/* Blocks are not adjacent */
+	block_len = a->len / bbl->block_size; /* rounds down */
+	if (a->block + block_len != b->block) {
+		return -EINVAL;
+	}
+
+	switch (a->type) {
+	case BACKED_BLOCK_DATA:
+		/* Don't support merging data for now */
+		return -EINVAL;
+	case BACKED_BLOCK_FILL:
+		if (a->fill.val != b->fill.val) {
+			return -EINVAL;
+		}
+		break;
+	case BACKED_BLOCK_FILE:
+		if (a->file.filename != b->file.filename ||
+				a->file.offset + a->len != b->file.offset) {
+			return -EINVAL;
+		}
+		break;
+	case BACKED_BLOCK_FD:
+		if (a->fd.fd != b->fd.fd ||
+				a->fd.offset + a->len != b->fd.offset) {
+			return -EINVAL;
+		}
+		break;
+	}
+
+	/* Blocks are compatible and adjacent, with a before b.  Merge b into a,
+	 * and free b */
+	a->len += b->len;
+	a->next = b->next;
+
+	backed_block_destroy(b);
+
+	return 0;
+}
+
+static int queue_bb(struct backed_block_list *bbl, struct backed_block *new_bb)
+{
+	struct backed_block *bb;
+
+	if (bbl->data_blocks == NULL) {
+		bbl->data_blocks = new_bb;
+		return 0;
+	}
+
+	if (bbl->data_blocks->block > new_bb->block) {
+		new_bb->next = bbl->data_blocks;
+		bbl->data_blocks = new_bb;
+		return 0;
+	}
+
+	/* Optimization: blocks are mostly queued in sequence, so save the
+	   pointer to the last bb that was added, and start searching from
+	   there if the next block number is higher */
+	if (bbl->last_used && new_bb->block > bbl->last_used->block)
+		bb = bbl->last_used;
+	else
+		bb = bbl->data_blocks;
+	bbl->last_used = new_bb;
+
+	for (; bb->next && bb->next->block < new_bb->block; bb = bb->next)
+		;
+
+	if (bb->next == NULL) {
+		bb->next = new_bb;
+	} else {
+		new_bb->next = bb->next;
+		bb->next = new_bb;
+	}
+
+	merge_bb(bbl, new_bb, new_bb->next);
+	merge_bb(bbl, bb, new_bb);
+
+	return 0;
+}
+
+/* Queues a fill block of memory to be written to the specified data blocks */
+int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val,
+		unsigned int len, unsigned int block)
+{
+	struct backed_block *bb = calloc(1, sizeof(struct backed_block));
+	if (bb == NULL) {
+		return -ENOMEM;
+	}
+
+	bb->block = block;
+	bb->len = len;
+	bb->type = BACKED_BLOCK_FILL;
+	bb->fill.val = fill_val;
+	bb->next = NULL;
+
+	return queue_bb(bbl, bb);
+}
+
+/* Queues a block of memory to be written to the specified data blocks */
+int backed_block_add_data(struct backed_block_list *bbl, void *data,
+		unsigned int len, unsigned int block)
+{
+	struct backed_block *bb = calloc(1, sizeof(struct backed_block));
+	if (bb == NULL) {
+		return -ENOMEM;
+	}
+
+	bb->block = block;
+	bb->len = len;
+	bb->type = BACKED_BLOCK_DATA;
+	bb->data.data = data;
+	bb->next = NULL;
+
+	return queue_bb(bbl, bb);
+}
+
+/* Queues a chunk of a file on disk to be written to the specified data blocks */
+int backed_block_add_file(struct backed_block_list *bbl, const char *filename,
+		int64_t offset, unsigned int len, unsigned int block)
+{
+	struct backed_block *bb = calloc(1, sizeof(struct backed_block));
+	if (bb == NULL) {
+		return -ENOMEM;
+	}
+
+	bb->block = block;
+	bb->len = len;
+	bb->type = BACKED_BLOCK_FILE;
+	bb->file.filename = strdup(filename);
+	bb->file.offset = offset;
+	bb->next = NULL;
+
+	return queue_bb(bbl, bb);
+}
+
+/* Queues a chunk of a fd to be written to the specified data blocks */
+int backed_block_add_fd(struct backed_block_list *bbl, int fd, int64_t offset,
+		unsigned int len, unsigned int block)
+{
+	struct backed_block *bb = calloc(1, sizeof(struct backed_block));
+	if (bb == NULL) {
+		return -ENOMEM;
+	}
+
+	bb->block = block;
+	bb->len = len;
+	bb->type = BACKED_BLOCK_FD;
+	bb->fd.fd = fd;
+	bb->fd.offset = offset;
+	bb->next = NULL;
+
+	return queue_bb(bbl, bb);
+}
+
+int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb,
+		unsigned int max_len)
+{
+	struct backed_block *new_bb;
+
+	max_len = ALIGN_DOWN(max_len, bbl->block_size);
+
+	if (bb->len <= max_len) {
+		return 0;
+	}
+
+	new_bb = malloc(sizeof(struct backed_block));
+	if (new_bb == NULL) {
+		return -ENOMEM;
+	}
+
+	*new_bb = *bb;
+
+	new_bb->len = bb->len - max_len;
+	new_bb->block = bb->block + max_len / bbl->block_size;
+	new_bb->next = bb->next;
+	bb->next = new_bb;
+	bb->len = max_len;
+
+	switch (bb->type) {
+	case BACKED_BLOCK_DATA:
+		new_bb->data.data = (char *)bb->data.data + max_len;
+		break;
+	case BACKED_BLOCK_FILE:
+		new_bb->file.offset += max_len;
+		break;
+	case BACKED_BLOCK_FD:
+		new_bb->fd.offset += max_len;
+		break;
+	case BACKED_BLOCK_FILL:
+		break;
+	}
+
+	return 0;
+}
diff --git a/distrib/libsparse/src/backed_block.h b/distrib/libsparse/src/backed_block.h
new file mode 100644
index 0000000..1a159be
--- /dev/null
+++ b/distrib/libsparse/src/backed_block.h
@@ -0,0 +1,64 @@
+/*
+ * 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 _BACKED_BLOCK_H_
+#define _BACKED_BLOCK_H_
+
+#include <stdint.h>
+
+struct backed_block_list;
+struct backed_block;
+
+enum backed_block_type {
+	BACKED_BLOCK_DATA,
+	BACKED_BLOCK_FILE,
+	BACKED_BLOCK_FD,
+	BACKED_BLOCK_FILL,
+};
+
+int backed_block_add_data(struct backed_block_list *bbl, void *data,
+		unsigned int len, unsigned int block);
+int backed_block_add_fill(struct backed_block_list *bbl, unsigned int fill_val,
+		unsigned int len, unsigned int block);
+int backed_block_add_file(struct backed_block_list *bbl, const char *filename,
+		int64_t offset, unsigned int len, unsigned int block);
+int backed_block_add_fd(struct backed_block_list *bbl, int fd,
+		int64_t offset, unsigned int len, unsigned int block);
+
+struct backed_block *backed_block_iter_new(struct backed_block_list *bbl);
+struct backed_block *backed_block_iter_next(struct backed_block *bb);
+unsigned int backed_block_len(struct backed_block *bb);
+unsigned int backed_block_block(struct backed_block *bb);
+void *backed_block_data(struct backed_block *bb);
+const char *backed_block_filename(struct backed_block *bb);
+int backed_block_fd(struct backed_block *bb);
+int64_t backed_block_file_offset(struct backed_block *bb);
+uint32_t backed_block_fill_val(struct backed_block *bb);
+enum backed_block_type backed_block_type(struct backed_block *bb);
+int backed_block_split(struct backed_block_list *bbl, struct backed_block *bb,
+		unsigned int max_len);
+
+struct backed_block *backed_block_iter_new(struct backed_block_list *bbl);
+struct backed_block *backed_block_iter_next(struct backed_block *bb);
+
+struct backed_block_list *backed_block_list_new(unsigned int block_size);
+void backed_block_list_destroy(struct backed_block_list *bbl);
+
+void backed_block_list_move(struct backed_block_list *from,
+		struct backed_block_list *to, struct backed_block *start,
+		struct backed_block *end);
+
+#endif
diff --git a/distrib/libsparse/src/defs.h b/distrib/libsparse/src/defs.h
new file mode 100644
index 0000000..34e63c5
--- /dev/null
+++ b/distrib/libsparse/src/defs.h
@@ -0,0 +1,23 @@
+/*
+ * 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 _LIBSPARSE_DEFS_H_
+
+#ifndef __unused
+#define __unused        __attribute__((__unused__))
+#endif
+
+#endif /* _LIBSPARSE_DEFS_H_ */
diff --git a/distrib/libsparse/src/img2simg.c b/distrib/libsparse/src/img2simg.c
new file mode 100644
index 0000000..a0db36f
--- /dev/null
+++ b/distrib/libsparse/src/img2simg.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 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 <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+void usage()
+{
+    fprintf(stderr, "Usage: img2simg <raw_image_file> <sparse_image_file> [<block_size>]\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int in;
+	int out;
+	int ret;
+	struct sparse_file *s;
+	unsigned int block_size = 4096;
+	off64_t len;
+
+	if (argc < 3 || argc > 4) {
+		usage();
+		exit(-1);
+	}
+
+	if (argc == 4) {
+		block_size = atoi(argv[3]);
+	}
+
+	if (block_size < 1024 || block_size % 4 != 0) {
+		usage();
+		exit(-1);
+	}
+
+	if (strcmp(argv[1], "-") == 0) {
+		in = STDIN_FILENO;
+	} else {
+		in = open(argv[1], O_RDONLY | O_BINARY);
+		if (in < 0) {
+			fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+			exit(-1);
+		}
+	}
+
+	if (strcmp(argv[2], "-") == 0) {
+		out = STDOUT_FILENO;
+	} else {
+		out = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
+		if (out < 0) {
+			fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+			exit(-1);
+		}
+	}
+
+	len = lseek64(in, 0, SEEK_END);
+	lseek64(in, 0, SEEK_SET);
+
+	s = sparse_file_new(block_size, len);
+	if (!s) {
+		fprintf(stderr, "Failed to create sparse file\n");
+		exit(-1);
+	}
+
+	sparse_file_verbose(s);
+	ret = sparse_file_read(s, in, false, false);
+	if (ret) {
+		fprintf(stderr, "Failed to read file\n");
+		exit(-1);
+	}
+
+	ret = sparse_file_write(s, out, false, true, false);
+	if (ret) {
+		fprintf(stderr, "Failed to write sparse file\n");
+		exit(-1);
+	}
+
+	close(in);
+	close(out);
+
+	exit(0);
+}
diff --git a/distrib/libsparse/src/output_file.c b/distrib/libsparse/src/output_file.c
new file mode 100644
index 0000000..cd30800
--- /dev/null
+++ b/distrib/libsparse/src/output_file.c
@@ -0,0 +1,766 @@
+/*
+ * 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 <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#include "defs.h"
+#include "output_file.h"
+#include "sparse_crc32.h"
+#include "sparse_format.h"
+
+#ifndef USE_MINGW
+#include <sys/mman.h>
+#define O_BINARY 0
+#else
+#define ftruncate64 ftruncate
+#endif
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define ftruncate64 ftruncate
+#define mmap64 mmap
+#define off64_t off_t
+#endif
+
+#define min(a, b) \
+	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
+
+#define SPARSE_HEADER_MAJOR_VER 1
+#define SPARSE_HEADER_MINOR_VER 0
+#define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
+#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
+
+#define container_of(inner, outer_t, elem) \
+	((outer_t *)((char *)inner - offsetof(outer_t, elem)))
+
+struct output_file_ops {
+	int (*open)(struct output_file *, int fd);
+	int (*skip)(struct output_file *, int64_t);
+	int (*pad)(struct output_file *, int64_t);
+	int (*write)(struct output_file *, void *, int);
+	void (*close)(struct output_file *);
+};
+
+struct sparse_file_ops {
+	int (*write_data_chunk)(struct output_file *out, unsigned int len,
+			void *data);
+	int (*write_fill_chunk)(struct output_file *out, unsigned int len,
+			uint32_t fill_val);
+	int (*write_skip_chunk)(struct output_file *out, int64_t len);
+	int (*write_end_chunk)(struct output_file *out);
+};
+
+struct output_file {
+	int64_t cur_out_ptr;
+	unsigned int chunk_cnt;
+	uint32_t crc32;
+	struct output_file_ops *ops;
+	struct sparse_file_ops *sparse_ops;
+	int use_crc;
+	unsigned int block_size;
+	int64_t len;
+	char *zero_buf;
+	uint32_t *fill_buf;
+	char *buf;
+};
+
+struct output_file_gz {
+	struct output_file out;
+	gzFile gz_fd;
+};
+
+#define to_output_file_gz(_o) \
+	container_of((_o), struct output_file_gz, out)
+
+struct output_file_normal {
+	struct output_file out;
+	int fd;
+};
+
+#define to_output_file_normal(_o) \
+	container_of((_o), struct output_file_normal, out)
+
+struct output_file_callback {
+	struct output_file out;
+	void *priv;
+	int (*write)(void *priv, const void *buf, int len);
+};
+
+#define to_output_file_callback(_o) \
+	container_of((_o), struct output_file_callback, out)
+
+static int file_open(struct output_file *out, int fd)
+{
+	struct output_file_normal *outn = to_output_file_normal(out);
+
+	outn->fd = fd;
+	return 0;
+}
+
+static int file_skip(struct output_file *out, int64_t cnt)
+{
+	off64_t ret;
+	struct output_file_normal *outn = to_output_file_normal(out);
+
+	ret = lseek64(outn->fd, cnt, SEEK_CUR);
+	if (ret < 0) {
+		error_errno("lseek64");
+		return -1;
+	}
+	return 0;
+}
+
+static int file_pad(struct output_file *out, int64_t len)
+{
+	int ret;
+	struct output_file_normal *outn = to_output_file_normal(out);
+
+	ret = ftruncate64(outn->fd, len);
+	if (ret < 0) {
+		return -errno;
+	}
+
+	return 0;
+}
+
+static int file_write(struct output_file *out, void *data, int len)
+{
+	int ret;
+	struct output_file_normal *outn = to_output_file_normal(out);
+
+	ret = write(outn->fd, data, len);
+	if (ret < 0) {
+		error_errno("write");
+		return -1;
+	} else if (ret < len) {
+		error("incomplete write");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void file_close(struct output_file *out)
+{
+	struct output_file_normal *outn = to_output_file_normal(out);
+
+	free(outn);
+}
+
+static struct output_file_ops file_ops = {
+	.open = file_open,
+	.skip = file_skip,
+	.pad = file_pad,
+	.write = file_write,
+	.close = file_close,
+};
+
+static int gz_file_open(struct output_file *out, int fd)
+{
+	struct output_file_gz *outgz = to_output_file_gz(out);
+
+	outgz->gz_fd = gzdopen(fd, "wb9");
+	if (!outgz->gz_fd) {
+		error_errno("gzopen");
+		return -errno;
+	}
+
+	return 0;
+}
+
+
+static int gz_file_skip(struct output_file *out, int64_t cnt)
+{
+	off64_t ret;
+	struct output_file_gz *outgz = to_output_file_gz(out);
+
+	ret = gzseek(outgz->gz_fd, cnt, SEEK_CUR);
+	if (ret < 0) {
+		error_errno("gzseek");
+		return -1;
+	}
+	return 0;
+}
+
+static int gz_file_pad(struct output_file *out, int64_t len)
+{
+	off64_t ret;
+	struct output_file_gz *outgz = to_output_file_gz(out);
+
+	ret = gztell(outgz->gz_fd);
+	if (ret < 0) {
+		return -1;
+	}
+
+	if (ret >= len) {
+		return 0;
+	}
+
+	ret = gzseek(outgz->gz_fd, len - 1, SEEK_SET);
+	if (ret < 0) {
+		return -1;
+	}
+
+	gzwrite(outgz->gz_fd, "", 1);
+
+	return 0;
+}
+
+static int gz_file_write(struct output_file *out, void *data, int len)
+{
+	int ret;
+	struct output_file_gz *outgz = to_output_file_gz(out);
+
+	ret = gzwrite(outgz->gz_fd, data, len);
+	if (ret < 0) {
+		error_errno("gzwrite");
+		return -1;
+	} else if (ret < len) {
+		error("incomplete gzwrite");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void gz_file_close(struct output_file *out)
+{
+	struct output_file_gz *outgz = to_output_file_gz(out);
+
+	gzclose(outgz->gz_fd);
+	free(outgz);
+}
+
+static struct output_file_ops gz_file_ops = {
+	.open = gz_file_open,
+	.skip = gz_file_skip,
+	.pad = gz_file_pad,
+	.write = gz_file_write,
+	.close = gz_file_close,
+};
+
+static int callback_file_open(struct output_file *out __unused, int fd __unused)
+{
+	return 0;
+}
+
+static int callback_file_skip(struct output_file *out, int64_t off)
+{
+	struct output_file_callback *outc = to_output_file_callback(out);
+	int to_write;
+	int ret;
+
+	while (off > 0) {
+		to_write = min(off, (int64_t)INT_MAX);
+		ret = outc->write(outc->priv, NULL, to_write);
+		if (ret < 0) {
+			return ret;
+		}
+		off -= to_write;
+	}
+
+	return 0;
+}
+
+static int callback_file_pad(struct output_file *out __unused, int64_t len __unused)
+{
+	return -1;
+}
+
+static int callback_file_write(struct output_file *out, void *data, int len)
+{
+	struct output_file_callback *outc = to_output_file_callback(out);
+
+	return outc->write(outc->priv, data, len);
+}
+
+static void callback_file_close(struct output_file *out)
+{
+	struct output_file_callback *outc = to_output_file_callback(out);
+
+	free(outc);
+}
+
+static struct output_file_ops callback_file_ops = {
+	.open = callback_file_open,
+	.skip = callback_file_skip,
+	.pad = callback_file_pad,
+	.write = callback_file_write,
+	.close = callback_file_close,
+};
+
+int read_all(int fd, void *buf, size_t len)
+{
+	size_t total = 0;
+	int ret;
+	char *ptr = buf;
+
+	while (total < len) {
+		ret = read(fd, ptr, len - total);
+
+		if (ret < 0)
+			return -errno;
+
+		if (ret == 0)
+			return -EINVAL;
+
+		ptr += ret;
+		total += ret;
+	}
+
+	return 0;
+}
+
+static int write_sparse_skip_chunk(struct output_file *out, int64_t skip_len)
+{
+	chunk_header_t chunk_header;
+	int ret;
+
+	if (skip_len % out->block_size) {
+		error("don't care size %"PRIi64" is not a multiple of the block size %u",
+				skip_len, out->block_size);
+		return -1;
+	}
+
+	/* We are skipping data, so emit a don't care chunk. */
+	chunk_header.chunk_type = CHUNK_TYPE_DONT_CARE;
+	chunk_header.reserved1 = 0;
+	chunk_header.chunk_sz = skip_len / out->block_size;
+	chunk_header.total_sz = CHUNK_HEADER_LEN;
+	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
+	if (ret < 0)
+		return -1;
+
+	out->cur_out_ptr += skip_len;
+	out->chunk_cnt++;
+
+	return 0;
+}
+
+static int write_sparse_fill_chunk(struct output_file *out, unsigned int len,
+		uint32_t fill_val)
+{
+	chunk_header_t chunk_header;
+	int rnd_up_len, count;
+	int ret;
+
+	/* Round up the fill length to a multiple of the block size */
+	rnd_up_len = ALIGN(len, out->block_size);
+
+	/* Finally we can safely emit a chunk of data */
+	chunk_header.chunk_type = CHUNK_TYPE_FILL;
+	chunk_header.reserved1 = 0;
+	chunk_header.chunk_sz = rnd_up_len / out->block_size;
+	chunk_header.total_sz = CHUNK_HEADER_LEN + sizeof(fill_val);
+	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
+
+	if (ret < 0)
+		return -1;
+	ret = out->ops->write(out, &fill_val, sizeof(fill_val));
+	if (ret < 0)
+		return -1;
+
+	if (out->use_crc) {
+		count = out->block_size / sizeof(uint32_t);
+		while (count--)
+			out->crc32 = sparse_crc32(out->crc32, &fill_val, sizeof(uint32_t));
+	}
+
+	out->cur_out_ptr += rnd_up_len;
+	out->chunk_cnt++;
+
+	return 0;
+}
+
+static int write_sparse_data_chunk(struct output_file *out, unsigned int len,
+		void *data)
+{
+	chunk_header_t chunk_header;
+	int rnd_up_len, zero_len;
+	int ret;
+
+	/* Round up the data length to a multiple of the block size */
+	rnd_up_len = ALIGN(len, out->block_size);
+	zero_len = rnd_up_len - len;
+
+	/* Finally we can safely emit a chunk of data */
+	chunk_header.chunk_type = CHUNK_TYPE_RAW;
+	chunk_header.reserved1 = 0;
+	chunk_header.chunk_sz = rnd_up_len / out->block_size;
+	chunk_header.total_sz = CHUNK_HEADER_LEN + rnd_up_len;
+	ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
+
+	if (ret < 0)
+		return -1;
+	ret = out->ops->write(out, data, len);
+	if (ret < 0)
+		return -1;
+	if (zero_len) {
+		ret = out->ops->write(out, out->zero_buf, zero_len);
+		if (ret < 0)
+			return -1;
+	}
+
+	if (out->use_crc) {
+		out->crc32 = sparse_crc32(out->crc32, data, len);
+		if (zero_len)
+			out->crc32 = sparse_crc32(out->crc32, out->zero_buf, zero_len);
+	}
+
+	out->cur_out_ptr += rnd_up_len;
+	out->chunk_cnt++;
+
+	return 0;
+}
+
+int write_sparse_end_chunk(struct output_file *out)
+{
+	chunk_header_t chunk_header;
+	int ret;
+
+	if (out->use_crc) {
+		chunk_header.chunk_type = CHUNK_TYPE_CRC32;
+		chunk_header.reserved1 = 0;
+		chunk_header.chunk_sz = 0;
+		chunk_header.total_sz = CHUNK_HEADER_LEN + 4;
+
+		ret = out->ops->write(out, &chunk_header, sizeof(chunk_header));
+		if (ret < 0) {
+			return ret;
+		}
+		out->ops->write(out, &out->crc32, 4);
+		if (ret < 0) {
+			return ret;
+		}
+
+		out->chunk_cnt++;
+	}
+
+	return 0;
+}
+
+static struct sparse_file_ops sparse_file_ops = {
+		.write_data_chunk = write_sparse_data_chunk,
+		.write_fill_chunk = write_sparse_fill_chunk,
+		.write_skip_chunk = write_sparse_skip_chunk,
+		.write_end_chunk = write_sparse_end_chunk,
+};
+
+static int write_normal_data_chunk(struct output_file *out, unsigned int len,
+		void *data)
+{
+	int ret;
+	unsigned int rnd_up_len = ALIGN(len, out->block_size);
+
+	ret = out->ops->write(out, data, len);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (rnd_up_len > len) {
+		ret = out->ops->skip(out, rnd_up_len - len);
+	}
+
+	return ret;
+}
+
+static int write_normal_fill_chunk(struct output_file *out, unsigned int len,
+		uint32_t fill_val)
+{
+	int ret;
+	unsigned int i;
+	unsigned int write_len;
+
+	/* Initialize fill_buf with the fill_val */
+	for (i = 0; i < out->block_size / sizeof(uint32_t); i++) {
+		out->fill_buf[i] = fill_val;
+	}
+
+	while (len) {
+		write_len = min(len, out->block_size);
+		ret = out->ops->write(out, out->fill_buf, write_len);
+		if (ret < 0) {
+			return ret;
+		}
+
+		len -= write_len;
+	}
+
+	return 0;
+}
+
+static int write_normal_skip_chunk(struct output_file *out, int64_t len)
+{
+	return out->ops->skip(out, len);
+}
+
+int write_normal_end_chunk(struct output_file *out)
+{
+	return out->ops->pad(out, out->len);
+}
+
+static struct sparse_file_ops normal_file_ops = {
+		.write_data_chunk = write_normal_data_chunk,
+		.write_fill_chunk = write_normal_fill_chunk,
+		.write_skip_chunk = write_normal_skip_chunk,
+		.write_end_chunk = write_normal_end_chunk,
+};
+
+void output_file_close(struct output_file *out)
+{
+	out->sparse_ops->write_end_chunk(out);
+	out->ops->close(out);
+}
+
+static int output_file_init(struct output_file *out, int block_size,
+		int64_t len, bool sparse, int chunks, bool crc)
+{
+	int ret;
+
+	out->len = len;
+	out->block_size = block_size;
+	out->cur_out_ptr = 0ll;
+	out->chunk_cnt = 0;
+	out->crc32 = 0;
+	out->use_crc = crc;
+
+	out->zero_buf = calloc(block_size, 1);
+	if (!out->zero_buf) {
+		error_errno("malloc zero_buf");
+		return -ENOMEM;
+	}
+
+	out->fill_buf = calloc(block_size, 1);
+	if (!out->fill_buf) {
+		error_errno("malloc fill_buf");
+		ret = -ENOMEM;
+		goto err_fill_buf;
+	}
+
+	if (sparse) {
+		out->sparse_ops = &sparse_file_ops;
+	} else {
+		out->sparse_ops = &normal_file_ops;
+	}
+
+	if (sparse) {
+		sparse_header_t sparse_header = {
+				.magic = SPARSE_HEADER_MAGIC,
+				.major_version = SPARSE_HEADER_MAJOR_VER,
+				.minor_version = SPARSE_HEADER_MINOR_VER,
+				.file_hdr_sz = SPARSE_HEADER_LEN,
+				.chunk_hdr_sz = CHUNK_HEADER_LEN,
+				.blk_sz = out->block_size,
+				.total_blks = out->len / out->block_size,
+				.total_chunks = chunks,
+				.image_checksum = 0
+		};
+
+		if (out->use_crc) {
+			sparse_header.total_chunks++;
+		}
+
+		ret = out->ops->write(out, &sparse_header, sizeof(sparse_header));
+		if (ret < 0) {
+			goto err_write;
+		}
+	}
+
+	return 0;
+
+err_write:
+	free(out->fill_buf);
+err_fill_buf:
+	free(out->zero_buf);
+	return ret;
+}
+
+static struct output_file *output_file_new_gz(void)
+{
+	struct output_file_gz *outgz = calloc(1, sizeof(struct output_file_gz));
+	if (!outgz) {
+		error_errno("malloc struct outgz");
+		return NULL;
+	}
+
+	outgz->out.ops = &gz_file_ops;
+
+	return &outgz->out;
+}
+
+static struct output_file *output_file_new_normal(void)
+{
+	struct output_file_normal *outn = calloc(1, sizeof(struct output_file_normal));
+	if (!outn) {
+		error_errno("malloc struct outn");
+		return NULL;
+	}
+
+	outn->out.ops = &file_ops;
+
+	return &outn->out;
+}
+
+struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+		void *priv, unsigned int block_size, int64_t len,
+		int gz __unused, int sparse, int chunks, int crc)
+{
+	int ret;
+	struct output_file_callback *outc;
+
+	outc = calloc(1, sizeof(struct output_file_callback));
+	if (!outc) {
+		error_errno("malloc struct outc");
+		return NULL;
+	}
+
+	outc->out.ops = &callback_file_ops;
+	outc->priv = priv;
+	outc->write = write;
+
+	ret = output_file_init(&outc->out, block_size, len, sparse, chunks, crc);
+	if (ret < 0) {
+		free(outc);
+		return NULL;
+	}
+
+	return &outc->out;
+}
+
+struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len,
+		int gz, int sparse, int chunks, int crc)
+{
+	int ret;
+	struct output_file *out;
+
+	if (gz) {
+		out = output_file_new_gz();
+	} else {
+		out = output_file_new_normal();
+	}
+	if (!out) {
+		return NULL;
+	}
+
+	out->ops->open(out, fd);
+
+	ret = output_file_init(out, block_size, len, sparse, chunks, crc);
+	if (ret < 0) {
+		free(out);
+		return NULL;
+	}
+
+	return out;
+}
+
+/* Write a contiguous region of data blocks from a memory buffer */
+int write_data_chunk(struct output_file *out, unsigned int len, void *data)
+{
+	return out->sparse_ops->write_data_chunk(out, len, data);
+}
+
+/* Write a contiguous region of data blocks with a fill value */
+int write_fill_chunk(struct output_file *out, unsigned int len,
+		uint32_t fill_val)
+{
+	return out->sparse_ops->write_fill_chunk(out, len, fill_val);
+}
+
+int write_fd_chunk(struct output_file *out, unsigned int len,
+		int fd, int64_t offset)
+{
+	int ret;
+	int64_t aligned_offset;
+	int aligned_diff;
+	int buffer_size;
+	char *ptr;
+
+	aligned_offset = offset & ~(4096 - 1);
+	aligned_diff = offset - aligned_offset;
+	buffer_size = len + aligned_diff;
+
+#ifndef USE_MINGW
+	char *data = mmap64(NULL, buffer_size, PROT_READ, MAP_SHARED, fd,
+			aligned_offset);
+	if (data == MAP_FAILED) {
+		return -errno;
+	}
+	ptr = data + aligned_diff;
+#else
+	off64_t pos;
+	char *data = malloc(len);
+	if (!data) {
+		return -errno;
+	}
+	pos = lseek64(fd, offset, SEEK_SET);
+	if (pos < 0) {
+                free(data);
+		return -errno;
+	}
+	ret = read_all(fd, data, len);
+	if (ret < 0) {
+                free(data);
+		return ret;
+	}
+	ptr = data;
+#endif
+
+	ret = out->sparse_ops->write_data_chunk(out, len, ptr);
+
+#ifndef USE_MINGW
+	munmap(data, buffer_size);
+#else
+	free(data);
+#endif
+
+	return ret;
+}
+
+/* Write a contiguous region of data blocks from a file */
+int write_file_chunk(struct output_file *out, unsigned int len,
+		const char *file, int64_t offset)
+{
+	int ret;
+
+	int file_fd = open(file, O_RDONLY | O_BINARY);
+	if (file_fd < 0) {
+		return -errno;
+	}
+
+	ret = write_fd_chunk(out, len, file_fd, offset);
+
+	close(file_fd);
+
+	return ret;
+}
+
+int write_skip_chunk(struct output_file *out, int64_t len)
+{
+	return out->sparse_ops->write_skip_chunk(out, len);
+}
diff --git a/distrib/libsparse/src/output_file.h b/distrib/libsparse/src/output_file.h
new file mode 100644
index 0000000..474c1fc
--- /dev/null
+++ b/distrib/libsparse/src/output_file.h
@@ -0,0 +1,41 @@
+/*
+ * 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 _OUTPUT_FILE_H_
+#define _OUTPUT_FILE_H_
+
+#include <sparse/sparse.h>
+
+struct output_file;
+
+struct output_file *output_file_open_fd(int fd, unsigned int block_size, int64_t len,
+		int gz, int sparse, int chunks, int crc);
+struct output_file *output_file_open_callback(int (*write)(void *, const void *, int),
+		void *priv, unsigned int block_size, int64_t len, int gz, int sparse,
+		int chunks, int crc);
+int write_data_chunk(struct output_file *out, unsigned int len, void *data);
+int write_fill_chunk(struct output_file *out, unsigned int len,
+		uint32_t fill_val);
+int write_file_chunk(struct output_file *out, unsigned int len,
+		const char *file, int64_t offset);
+int write_fd_chunk(struct output_file *out, unsigned int len,
+		int fd, int64_t offset);
+int write_skip_chunk(struct output_file *out, int64_t len);
+void output_file_close(struct output_file *out);
+
+int read_all(int fd, void *buf, size_t len);
+
+#endif
diff --git a/distrib/libsparse/src/simg2img.c b/distrib/libsparse/src/simg2img.c
new file mode 100644
index 0000000..95e9b5b
--- /dev/null
+++ b/distrib/libsparse/src/simg2img.c
@@ -0,0 +1,89 @@
+/*
+ * 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 <sparse/sparse.h>
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+void usage()
+{
+  fprintf(stderr, "Usage: simg2img <sparse_image_files> <raw_image_file>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int in;
+	int out;
+	int i;
+	int ret;
+	struct sparse_file *s;
+
+	if (argc < 3) {
+		usage();
+		exit(-1);
+	}
+
+	out = open(argv[argc - 1], O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
+	if (out < 0) {
+		fprintf(stderr, "Cannot open output file %s\n", argv[argc - 1]);
+		exit(-1);
+	}
+
+	for (i = 1; i < argc - 1; i++) {
+		if (strcmp(argv[i], "-") == 0) {
+			in = STDIN_FILENO;
+		} else {
+			in = open(argv[i], O_RDONLY | O_BINARY);
+			if (in < 0) {
+				fprintf(stderr, "Cannot open input file %s\n", argv[i]);
+				exit(-1);
+			}
+		}
+
+		s = sparse_file_import(in, true, false);
+		if (!s) {
+			fprintf(stderr, "Failed to read sparse file\n");
+			exit(-1);
+		}
+
+		lseek(out, SEEK_SET, 0);
+
+		ret = sparse_file_write(s, out, false, false, false);
+		if (ret < 0) {
+			fprintf(stderr, "Cannot write output file\n");
+			exit(-1);
+		}
+		sparse_file_destroy(s);
+		close(in);
+	}
+
+	close(out);
+
+	exit(0);
+}
+
diff --git a/distrib/libsparse/src/simg2simg.c b/distrib/libsparse/src/simg2simg.c
new file mode 100644
index 0000000..5f9ccf6
--- /dev/null
+++ b/distrib/libsparse/src/simg2simg.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2012 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
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+void usage()
+{
+  fprintf(stderr, "Usage: simg2simg <sparse image file> <sparse_image_file> <max_size>\n");
+}
+
+int main(int argc, char *argv[])
+{
+	int in;
+	int out;
+	int i;
+	int ret;
+	struct sparse_file *s;
+	int64_t max_size;
+	struct sparse_file **out_s;
+	int files;
+	char filename[4096];
+
+	if (argc != 4) {
+		usage();
+		exit(-1);
+	}
+
+	max_size = atoll(argv[3]);
+
+	in = open(argv[1], O_RDONLY | O_BINARY);
+	if (in < 0) {
+		fprintf(stderr, "Cannot open input file %s\n", argv[1]);
+		exit(-1);
+	}
+
+	s = sparse_file_import(in, true, false);
+	if (!s) {
+		fprintf(stderr, "Failed to import sparse file\n");
+		exit(-1);
+	}
+
+	files = sparse_file_resparse(s, max_size, NULL, 0);
+	if (files < 0) {
+		fprintf(stderr, "Failed to resparse\n");
+		exit(-1);
+	}
+
+	out_s = calloc(sizeof(struct sparse_file *), files);
+	if (!out_s) {
+		fprintf(stderr, "Failed to allocate sparse file array\n");
+		exit(-1);
+	}
+
+	files = sparse_file_resparse(s, max_size, out_s, files);
+	if (files < 0) {
+		fprintf(stderr, "Failed to resparse\n");
+		exit(-1);
+	}
+
+	for (i = 0; i < files; i++) {
+		ret = snprintf(filename, sizeof(filename), "%s.%d", argv[2], i);
+		if (ret >= (int)sizeof(filename)) {
+			fprintf(stderr, "Filename too long\n");
+			exit(-1);
+		}
+
+		out = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0664);
+		if (out < 0) {
+			fprintf(stderr, "Cannot open output file %s\n", argv[2]);
+			exit(-1);
+		}
+
+		ret = sparse_file_write(out_s[i], out, false, true, false);
+		if (ret) {
+			fprintf(stderr, "Failed to write sparse file\n");
+			exit(-1);
+		}
+		close(out);
+	}
+
+	close(in);
+
+	exit(0);
+}
diff --git a/distrib/libsparse/src/simg_dump.py b/distrib/libsparse/src/simg_dump.py
new file mode 100755
index 0000000..6ece31d
--- /dev/null
+++ b/distrib/libsparse/src/simg_dump.py
@@ -0,0 +1,169 @@
+#! /usr/bin/env python
+
+# Copyright (C) 2012 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.
+
+from __future__ import print_function
+import getopt, posixpath, signal, struct, sys
+
+def usage(argv0):
+  print("""
+Usage: %s [-v] sparse_image_file ...
+ -v             verbose output
+""" % ( argv0 ))
+  sys.exit(2)
+
+def main():
+
+  signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
+  me = posixpath.basename(sys.argv[0])
+
+  # Parse the command line
+  verbose = 0			# -v
+  try:
+    opts, args = getopt.getopt(sys.argv[1:],
+                               "v",
+                               ["verbose"])
+  except getopt.GetoptError, e:
+    print(e)
+    usage(me)
+  for o, a in opts:
+    if o in ("-v", "--verbose"):
+      verbose += 1
+    else:
+      print("Unrecognized option \"%s\"" % (o))
+      usage(me)
+
+  if len(args) == 0:
+    print("No sparse_image_file specified")
+    usage(me)
+
+  for path in args:
+    FH = open(path, 'rb')
+    header_bin = FH.read(28)
+    header = struct.unpack("<I4H4I", header_bin)
+
+    magic = header[0]
+    major_version = header[1]
+    minor_version = header[2]
+    file_hdr_sz = header[3]
+    chunk_hdr_sz = header[4]
+    blk_sz = header[5]
+    total_blks = header[6]
+    total_chunks = header[7]
+    image_checksum = header[8]
+
+    if magic != 0xED26FF3A:
+      print("%s: %s: Magic should be 0xED26FF3A but is 0x%08X"
+            % (me, path, magic))
+      continue
+    if major_version != 1 or minor_version != 0:
+      print("%s: %s: I only know about version 1.0, but this is version %u.%u"
+            % (me, path, major_version, minor_version))
+      continue
+    if file_hdr_sz != 28:
+      print("%s: %s: The file header size was expected to be 28, but is %u."
+            % (me, path, file_hdr_sz))
+      continue
+    if chunk_hdr_sz != 12:
+      print("%s: %s: The chunk header size was expected to be 12, but is %u."
+            % (me, path, chunk_hdr_sz))
+      continue
+
+    print("%s: Total of %u %u-byte output blocks in %u input chunks."
+          % (path, total_blks, blk_sz, total_chunks))
+
+    if image_checksum != 0:
+      print("checksum=0x%08X" % (image_checksum))
+
+    if not verbose:
+      continue
+    print("            input_bytes      output_blocks")
+    print("chunk    offset     number  offset  number")
+    offset = 0
+    for i in xrange(1,total_chunks+1):
+      header_bin = FH.read(12)
+      header = struct.unpack("<2H2I", header_bin)
+      chunk_type = header[0]
+      reserved1 = header[1]
+      chunk_sz = header[2]
+      total_sz = header[3]
+      data_sz = total_sz - 12
+
+      print("%4u %10u %10u %7u %7u" % (i, FH.tell(), data_sz, offset, chunk_sz),
+            end=" ")
+
+      if chunk_type == 0xCAC1:
+        if data_sz != (chunk_sz * blk_sz):
+          print("Raw chunk input size (%u) does not match output size (%u)"
+                % (data_sz, chunk_sz * blk_sz))
+          break;
+        else:
+          print("Raw data", end="")
+          FH.read(data_sz)
+      elif chunk_type == 0xCAC2:
+        if data_sz != 4:
+          print("Fill chunk should have 4 bytes of fill, but this has %u"
+                % (data_sz), end="")
+          break;
+        else:
+          fill_bin = FH.read(4)
+          fill = struct.unpack("<I", fill_bin)
+          print("Fill with 0x%08X" % (fill))
+      elif chunk_type == 0xCAC3:
+        if data_sz != 0:
+          print("Don't care chunk input size is non-zero (%u)" % (data_sz))
+          break;
+        else:
+          print("Don't care", end="")
+      elif chunk_type == 0xCAC4:
+        if data_sz != 4:
+          print("CRC32 chunk should have 4 bytes of CRC, but this has %u"
+                % (data_sz), end="")
+          break;
+        else:
+          crc_bin = FH.read(4)
+          crc = struct.unpack("<I", crc)
+          print("Unverified CRC32 0x%08X" % (crc))
+      else:
+          print("Unknown chunk type 0x%04X" % (chunk_type), end="")
+          break;
+
+      if verbose > 1:
+        header = struct.unpack("<12B", header_bin)
+        print(" (%02X%02X %02X%02X %02X%02X%02X%02X %02X%02X%02X%02X)"
+              % (header[0], header[1], header[2], header[3],
+                 header[4], header[5], header[6], header[7],
+                 header[8], header[9], header[10], header[11]))
+      else:
+        print()
+
+      offset += chunk_sz
+
+    print("     %10u            %7u         End" % (FH.tell(), offset))
+
+    if total_blks != offset:
+      print("The header said we should have %u output blocks, but we saw %u"
+            % (total_blks, offset))
+
+    junk_len = len(FH.read())
+    if junk_len:
+      print("There were %u bytes of extra data at the end of the file."
+            % (junk_len))
+
+  sys.exit(0)
+
+if __name__ == "__main__":
+  main()
diff --git a/distrib/libsparse/src/sparse.c b/distrib/libsparse/src/sparse.c
new file mode 100644
index 0000000..baa30cd
--- /dev/null
+++ b/distrib/libsparse/src/sparse.c
@@ -0,0 +1,317 @@
+/*
+ * Copyright (C) 2012 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 <assert.h>
+#include <stdlib.h>
+
+#include <sparse/sparse.h>
+
+#include "defs.h"
+#include "sparse_file.h"
+
+#include "output_file.h"
+#include "backed_block.h"
+#include "sparse_defs.h"
+#include "sparse_format.h"
+
+struct sparse_file *sparse_file_new(unsigned int block_size, int64_t len)
+{
+	struct sparse_file *s = calloc(sizeof(struct sparse_file), 1);
+	if (!s) {
+		return NULL;
+	}
+
+	s->backed_block_list = backed_block_list_new(block_size);
+	if (!s->backed_block_list) {
+		free(s);
+		return NULL;
+	}
+
+	s->block_size = block_size;
+	s->len = len;
+
+	return s;
+}
+
+void sparse_file_destroy(struct sparse_file *s)
+{
+	backed_block_list_destroy(s->backed_block_list);
+	free(s);
+}
+
+int sparse_file_add_data(struct sparse_file *s,
+		void *data, unsigned int len, unsigned int block)
+{
+	return backed_block_add_data(s->backed_block_list, data, len, block);
+}
+
+int sparse_file_add_fill(struct sparse_file *s,
+		uint32_t fill_val, unsigned int len, unsigned int block)
+{
+	return backed_block_add_fill(s->backed_block_list, fill_val, len, block);
+}
+
+int sparse_file_add_file(struct sparse_file *s,
+		const char *filename, int64_t file_offset, unsigned int len,
+		unsigned int block)
+{
+	return backed_block_add_file(s->backed_block_list, filename, file_offset,
+			len, block);
+}
+
+int sparse_file_add_fd(struct sparse_file *s,
+		int fd, int64_t file_offset, unsigned int len, unsigned int block)
+{
+	return backed_block_add_fd(s->backed_block_list, fd, file_offset,
+			len, block);
+}
+unsigned int sparse_count_chunks(struct sparse_file *s)
+{
+	struct backed_block *bb;
+	unsigned int last_block = 0;
+	unsigned int chunks = 0;
+
+	for (bb = backed_block_iter_new(s->backed_block_list); bb;
+			bb = backed_block_iter_next(bb)) {
+		if (backed_block_block(bb) > last_block) {
+			/* If there is a gap between chunks, add a skip chunk */
+			chunks++;
+		}
+		chunks++;
+		last_block = backed_block_block(bb) +
+				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
+	}
+	if (last_block < DIV_ROUND_UP(s->len, s->block_size)) {
+		chunks++;
+	}
+
+	return chunks;
+}
+
+static void sparse_file_write_block(struct output_file *out,
+		struct backed_block *bb)
+{
+	switch (backed_block_type(bb)) {
+	case BACKED_BLOCK_DATA:
+		write_data_chunk(out, backed_block_len(bb), backed_block_data(bb));
+		break;
+	case BACKED_BLOCK_FILE:
+		write_file_chunk(out, backed_block_len(bb),
+				backed_block_filename(bb), backed_block_file_offset(bb));
+		break;
+	case BACKED_BLOCK_FD:
+		write_fd_chunk(out, backed_block_len(bb),
+				backed_block_fd(bb), backed_block_file_offset(bb));
+		break;
+	case BACKED_BLOCK_FILL:
+		write_fill_chunk(out, backed_block_len(bb),
+				backed_block_fill_val(bb));
+		break;
+	}
+}
+
+static int write_all_blocks(struct sparse_file *s, struct output_file *out)
+{
+	struct backed_block *bb;
+	unsigned int last_block = 0;
+	int64_t pad;
+
+	for (bb = backed_block_iter_new(s->backed_block_list); bb;
+			bb = backed_block_iter_next(bb)) {
+		if (backed_block_block(bb) > last_block) {
+			unsigned int blocks = backed_block_block(bb) - last_block;
+			write_skip_chunk(out, (int64_t)blocks * s->block_size);
+		}
+		sparse_file_write_block(out, bb);
+		last_block = backed_block_block(bb) +
+				DIV_ROUND_UP(backed_block_len(bb), s->block_size);
+	}
+
+	pad = s->len - (int64_t)last_block * s->block_size;
+	assert(pad >= 0);
+	if (pad > 0) {
+		write_skip_chunk(out, pad);
+	}
+
+	return 0;
+}
+
+int sparse_file_write(struct sparse_file *s, int fd, bool gz, bool sparse,
+		bool crc)
+{
+	int ret;
+	int chunks;
+	struct output_file *out;
+
+	chunks = sparse_count_chunks(s);
+	out = output_file_open_fd(fd, s->block_size, s->len, gz, sparse, chunks, crc);
+
+	if (!out)
+		return -ENOMEM;
+
+	ret = write_all_blocks(s, out);
+
+	output_file_close(out);
+
+	return ret;
+}
+
+int sparse_file_callback(struct sparse_file *s, bool sparse, bool crc,
+		int (*write)(void *priv, const void *data, int len), void *priv)
+{
+	int ret;
+	int chunks;
+	struct output_file *out;
+
+	chunks = sparse_count_chunks(s);
+	out = output_file_open_callback(write, priv, s->block_size, s->len, false,
+			sparse, chunks, crc);
+
+	if (!out)
+		return -ENOMEM;
+
+	ret = write_all_blocks(s, out);
+
+	output_file_close(out);
+
+	return ret;
+}
+
+static int out_counter_write(void *priv, const void *data __unused, int len)
+{
+	int64_t *count = priv;
+	*count += len;
+	return 0;
+}
+
+int64_t sparse_file_len(struct sparse_file *s, bool sparse, bool crc)
+{
+	int ret;
+	int chunks = sparse_count_chunks(s);
+	int64_t count = 0;
+	struct output_file *out;
+
+	out = output_file_open_callback(out_counter_write, &count,
+			s->block_size, s->len, false, sparse, chunks, crc);
+	if (!out) {
+		return -1;
+	}
+
+	ret = write_all_blocks(s, out);
+
+	output_file_close(out);
+
+	if (ret < 0) {
+		return -1;
+	}
+
+	return count;
+}
+
+static struct backed_block *move_chunks_up_to_len(struct sparse_file *from,
+		struct sparse_file *to, unsigned int len)
+{
+	int64_t count = 0;
+	struct output_file *out_counter;
+	struct backed_block *last_bb = NULL;
+	struct backed_block *bb;
+	struct backed_block *start;
+	int64_t file_len = 0;
+
+	/*
+	 * overhead is sparse file header, initial skip chunk, split chunk, end
+	 * skip chunk, and crc chunk.
+	 */
+	int overhead = sizeof(sparse_header_t) + 4 * sizeof(chunk_header_t) +
+			sizeof(uint32_t);
+	len -= overhead;
+
+	start = backed_block_iter_new(from->backed_block_list);
+	out_counter = output_file_open_callback(out_counter_write, &count,
+			to->block_size, to->len, false, true, 0, false);
+	if (!out_counter) {
+		return NULL;
+	}
+
+	for (bb = start; bb; bb = backed_block_iter_next(bb)) {
+		count = 0;
+		/* will call out_counter_write to update count */
+		sparse_file_write_block(out_counter, bb);
+		if (file_len + count > len) {
+			/*
+			 * If the remaining available size is more than 1/8th of the
+			 * requested size, split the chunk.  Results in sparse files that
+			 * are at least 7/8ths of the requested size
+			 */
+			if (!last_bb || (len - file_len > (len / 8))) {
+				backed_block_split(from->backed_block_list, bb, len - file_len);
+				last_bb = bb;
+			}
+			goto out;
+		}
+		file_len += count;
+		last_bb = bb;
+	}
+
+out:
+	backed_block_list_move(from->backed_block_list,
+		to->backed_block_list, start, last_bb);
+
+	output_file_close(out_counter);
+
+	return bb;
+}
+
+int sparse_file_resparse(struct sparse_file *in_s, unsigned int max_len,
+		struct sparse_file **out_s, int out_s_count)
+{
+	struct backed_block *bb;
+	struct sparse_file *s;
+	struct sparse_file *tmp;
+	int c = 0;
+
+	tmp = sparse_file_new(in_s->block_size, in_s->len);
+	if (!tmp) {
+		return -ENOMEM;
+	}
+
+	do {
+		s = sparse_file_new(in_s->block_size, in_s->len);
+
+		bb = move_chunks_up_to_len(in_s, s, max_len);
+
+		if (c < out_s_count) {
+			out_s[c] = s;
+		} else {
+			backed_block_list_move(s->backed_block_list, tmp->backed_block_list,
+					NULL, NULL);
+			sparse_file_destroy(s);
+		}
+		c++;
+	} while (bb);
+
+	backed_block_list_move(tmp->backed_block_list, in_s->backed_block_list,
+			NULL, NULL);
+
+	sparse_file_destroy(tmp);
+
+	return c;
+}
+
+void sparse_file_verbose(struct sparse_file *s)
+{
+	s->verbose = true;
+}
diff --git a/distrib/libsparse/src/sparse_crc32.c b/distrib/libsparse/src/sparse_crc32.c
new file mode 100644
index 0000000..38bfe4a
--- /dev/null
+++ b/distrib/libsparse/src/sparse_crc32.c
@@ -0,0 +1,111 @@
+/*-
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ */
+
+/*
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to hight-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera
+ *      tions for all combinations of data and CRC register values
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions
+ *      polynomial $edb88320
+ *
+ *
+ * CRC32 code derived from work by Gary S. Brown.
+ */
+
+/* Code taken from FreeBSD 8 */
+#include <stdint.h>
+
+static uint32_t crc32_tab[] = {
+        0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+        0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+        0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+        0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+        0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+        0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+        0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+        0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+        0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+        0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+        0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+        0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+        0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+        0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+        0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+        0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+        0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+        0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+        0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+        0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+        0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+        0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+        0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+        0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+        0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+        0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+        0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+        0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+        0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+        0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+        0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+        0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+        0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+        0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+        0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+        0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+        0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+        0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+        0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+/*
+ * A function that calculates the CRC-32 based on the table above is
+ * given below for documentation purposes. An equivalent implementation
+ * of this function that's actually used in the kernel can be found
+ * in sys/libkern.h, where it can be inlined.
+ */
+
+uint32_t sparse_crc32(uint32_t crc_in, const void *buf, int size)
+{
+        const uint8_t *p = buf;
+        uint32_t crc;
+
+        crc = crc_in ^ ~0U;
+        while (size--)
+                crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+        return crc ^ ~0U;
+}
+
diff --git a/distrib/libsparse/src/sparse_crc32.h b/distrib/libsparse/src/sparse_crc32.h
new file mode 100644
index 0000000..cad8a86
--- /dev/null
+++ b/distrib/libsparse/src/sparse_crc32.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.
+ */
+
+#include <stdint.h>
+
+uint32_t sparse_crc32(uint32_t crc, const void *buf, size_t size);
+
diff --git a/distrib/libsparse/src/sparse_defs.h b/distrib/libsparse/src/sparse_defs.h
new file mode 100644
index 0000000..b99cfd5
--- /dev/null
+++ b/distrib/libsparse/src/sparse_defs.h
@@ -0,0 +1,49 @@
+/*
+ * 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 _LIBSPARSE_SPARSE_DEFS_
+#define _LIBSPARSE_SPARSE_DEFS_
+
+#include <errno.h>
+#include <stdio.h>
+
+#define __le64 u64
+#define __le32 u32
+#define __le16 u16
+
+#define __be64 u64
+#define __be32 u32
+#define __be16 u16
+
+#define __u64 u64
+#define __u32 u32
+#define __u16 u16
+#define __u8 u8
+
+typedef unsigned long long u64;
+typedef signed long long s64;
+typedef unsigned int u32;
+typedef unsigned short int u16;
+typedef unsigned char u8;
+
+#define DIV_ROUND_UP(x, y) (((x) + (y) - 1)/(y))
+#define ALIGN(x, y) ((y) * DIV_ROUND_UP((x), (y)))
+#define ALIGN_DOWN(x, y) ((y) * ((x) / (y)))
+
+#define error(fmt, args...) do { fprintf(stderr, "error: %s: " fmt "\n", __func__, ## args); } while (0)
+#define error_errno(s, args...) error(s ": %s", ##args, strerror(errno))
+
+#endif
diff --git a/distrib/libsparse/src/sparse_err.c b/distrib/libsparse/src/sparse_err.c
new file mode 100644
index 0000000..0f392ad
--- /dev/null
+++ b/distrib/libsparse/src/sparse_err.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2012 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 <sparse/sparse.h>
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void sparse_default_print(const char *fmt, ...)
+{
+	va_list argp;
+
+	va_start(argp, fmt);
+	vfprintf(stderr, fmt, argp);
+	va_end(argp);
+}
+
+void (*sparse_print_error)(const char *fmt, ...) = sparse_default_print;
+void (*sparse_print_verbose)(const char *fmt, ...) = sparse_default_print;
diff --git a/distrib/libsparse/src/sparse_file.h b/distrib/libsparse/src/sparse_file.h
new file mode 100644
index 0000000..91a12e6
--- /dev/null
+++ b/distrib/libsparse/src/sparse_file.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 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 _LIBSPARSE_SPARSE_FILE_H_
+#define _LIBSPARSE_SPARSE_FILE_H_
+
+#include <sparse/sparse.h>
+
+struct sparse_file {
+	unsigned int block_size;
+	int64_t len;
+	bool verbose;
+
+	struct backed_block_list *backed_block_list;
+	struct output_file *out;
+};
+
+
+#endif /* _LIBSPARSE_SPARSE_FILE_H_ */
diff --git a/distrib/libsparse/src/sparse_format.h b/distrib/libsparse/src/sparse_format.h
new file mode 100644
index 0000000..c41f12a
--- /dev/null
+++ b/distrib/libsparse/src/sparse_format.h
@@ -0,0 +1,55 @@
+/*
+ * 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 _LIBSPARSE_SPARSE_FORMAT_H_
+#define _LIBSPARSE_SPARSE_FORMAT_H_
+#include "sparse_defs.h"
+
+typedef struct sparse_header {
+  __le32	magic;		/* 0xed26ff3a */
+  __le16	major_version;	/* (0x1) - reject images with higher major versions */
+  __le16	minor_version;	/* (0x0) - allow images with higer minor versions */
+  __le16	file_hdr_sz;	/* 28 bytes for first revision of the file format */
+  __le16	chunk_hdr_sz;	/* 12 bytes for first revision of the file format */
+  __le32	blk_sz;		/* block size in bytes, must be a multiple of 4 (4096) */
+  __le32	total_blks;	/* total blocks in the non-sparse output image */
+  __le32	total_chunks;	/* total chunks in the sparse input image */
+  __le32	image_checksum; /* CRC32 checksum of the original data, counting "don't care" */
+				/* as 0. Standard 802.3 polynomial, use a Public Domain */
+				/* table implementation */
+} sparse_header_t;
+
+#define SPARSE_HEADER_MAGIC	0xed26ff3a
+
+#define CHUNK_TYPE_RAW		0xCAC1
+#define CHUNK_TYPE_FILL		0xCAC2
+#define CHUNK_TYPE_DONT_CARE	0xCAC3
+#define CHUNK_TYPE_CRC32    0xCAC4
+
+typedef struct chunk_header {
+  __le16	chunk_type;	/* 0xCAC1 -> raw; 0xCAC2 -> fill; 0xCAC3 -> don't care */
+  __le16	reserved1;
+  __le32	chunk_sz;	/* in blocks in output image */
+  __le32	total_sz;	/* in bytes of chunk input file including chunk header and data */
+} chunk_header_t;
+
+/* Following a Raw or Fill or CRC32 chunk is data.
+ *  For a Raw chunk, it's the data in chunk_sz * blk_sz.
+ *  For a Fill chunk, it's 4 bytes of the fill data.
+ *  For a CRC32 chunk, it's 4 bytes of CRC32
+ */
+
+#endif
diff --git a/distrib/libsparse/src/sparse_read.c b/distrib/libsparse/src/sparse_read.c
new file mode 100644
index 0000000..8e188e9
--- /dev/null
+++ b/distrib/libsparse/src/sparse_read.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2012 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 _GNU_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE 1
+
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sparse/sparse.h>
+
+#include "defs.h"
+#include "output_file.h"
+#include "sparse_crc32.h"
+#include "sparse_file.h"
+#include "sparse_format.h"
+
+#if defined(__APPLE__) && defined(__MACH__)
+#define lseek64 lseek
+#define off64_t off_t
+#endif
+
+#define SPARSE_HEADER_MAJOR_VER 1
+#define SPARSE_HEADER_LEN       (sizeof(sparse_header_t))
+#define CHUNK_HEADER_LEN (sizeof(chunk_header_t))
+
+#define COPY_BUF_SIZE (1024U*1024U)
+static char *copybuf;
+
+#define min(a, b) \
+	({ typeof(a) _a = (a); typeof(b) _b = (b); (_a < _b) ? _a : _b; })
+
+static void verbose_error(bool verbose, int err, const char *fmt, ...)
+{
+	char *s = "";
+	char *at = "";
+	if (fmt) {
+		va_list argp;
+		int size;
+
+		va_start(argp, fmt);
+		size = vsnprintf(NULL, 0, fmt, argp);
+		va_end(argp);
+
+		if (size < 0) {
+			return;
+		}
+
+		at = malloc(size + 1);
+		if (at == NULL) {
+			return;
+		}
+
+		va_start(argp, fmt);
+		vsnprintf(at, size, fmt, argp);
+		va_end(argp);
+		at[size] = 0;
+		s = " at ";
+	}
+	if (verbose) {
+#ifndef USE_MINGW
+		if (err == -EOVERFLOW) {
+			sparse_print_verbose("EOF while reading file%s%s\n", s, at);
+		} else
+#endif
+		if (err == -EINVAL) {
+			sparse_print_verbose("Invalid sparse file format%s%s\n", s, at);
+		} else if (err == -ENOMEM) {
+			sparse_print_verbose("Failed allocation while reading file%s%s\n",
+					s, at);
+		} else {
+			sparse_print_verbose("Unknown error %d%s%s\n", err, s, at);
+		}
+	}
+	if (fmt) {
+		free(at);
+	}
+}
+
+static int process_raw_chunk(struct sparse_file *s, unsigned int chunk_size,
+		int fd, int64_t offset, unsigned int blocks, unsigned int block,
+		uint32_t *crc32)
+{
+	int ret;
+	int chunk;
+	unsigned int len = blocks * s->block_size;
+
+	if (chunk_size % s->block_size != 0) {
+		return -EINVAL;
+	}
+
+	if (chunk_size / s->block_size != blocks) {
+		return -EINVAL;
+	}
+
+	ret = sparse_file_add_fd(s, fd, offset, len, block);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (crc32) {
+		while (len) {
+			chunk = min(len, COPY_BUF_SIZE);
+			ret = read_all(fd, copybuf, chunk);
+			if (ret < 0) {
+				return ret;
+			}
+			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
+			len -= chunk;
+		}
+	} else {
+		lseek64(fd, len, SEEK_CUR);
+	}
+
+	return 0;
+}
+
+static int process_fill_chunk(struct sparse_file *s, unsigned int chunk_size,
+		int fd, unsigned int blocks, unsigned int block, uint32_t *crc32)
+{
+	int ret;
+	int chunk;
+	int64_t len = (int64_t)blocks * s->block_size;
+	uint32_t fill_val;
+	uint32_t *fillbuf;
+	unsigned int i;
+
+	if (chunk_size != sizeof(fill_val)) {
+		return -EINVAL;
+	}
+
+	ret = read_all(fd, &fill_val, sizeof(fill_val));
+	if (ret < 0) {
+		return ret;
+	}
+
+	ret = sparse_file_add_fill(s, fill_val, len, block);
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (crc32) {
+		/* Fill copy_buf with the fill value */
+		fillbuf = (uint32_t *)copybuf;
+		for (i = 0; i < (COPY_BUF_SIZE / sizeof(fill_val)); i++) {
+			fillbuf[i] = fill_val;
+		}
+
+		while (len) {
+			chunk = min(len, COPY_BUF_SIZE);
+			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
+			len -= chunk;
+		}
+	}
+
+	return 0;
+}
+
+static int process_skip_chunk(struct sparse_file *s, unsigned int chunk_size,
+		int fd __unused, unsigned int blocks,
+		unsigned int block __unused, uint32_t *crc32)
+{
+	if (chunk_size != 0) {
+		return -EINVAL;
+	}
+
+	if (crc32) {
+	        int64_t len = (int64_t)blocks * s->block_size;
+		memset(copybuf, 0, COPY_BUF_SIZE);
+
+		while (len) {
+			int chunk = min(len, COPY_BUF_SIZE);
+			*crc32 = sparse_crc32(*crc32, copybuf, chunk);
+			len -= chunk;
+		}
+	}
+
+	return 0;
+}
+
+static int process_crc32_chunk(int fd, unsigned int chunk_size, uint32_t crc32)
+{
+	uint32_t file_crc32;
+	int ret;
+
+	if (chunk_size != sizeof(file_crc32)) {
+		return -EINVAL;
+	}
+
+	ret = read_all(fd, &file_crc32, sizeof(file_crc32));
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (file_crc32 != crc32) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int process_chunk(struct sparse_file *s, int fd, off64_t offset,
+		unsigned int chunk_hdr_sz, chunk_header_t *chunk_header,
+		unsigned int cur_block, uint32_t *crc_ptr)
+{
+	int ret;
+	unsigned int chunk_data_size;
+
+	chunk_data_size = chunk_header->total_sz - chunk_hdr_sz;
+
+	switch (chunk_header->chunk_type) {
+		case CHUNK_TYPE_RAW:
+			ret = process_raw_chunk(s, chunk_data_size, fd, offset,
+					chunk_header->chunk_sz, cur_block, crc_ptr);
+			if (ret < 0) {
+				verbose_error(s->verbose, ret, "data block at %lld", offset);
+				return ret;
+			}
+			return chunk_header->chunk_sz;
+		case CHUNK_TYPE_FILL:
+			ret = process_fill_chunk(s, chunk_data_size, fd,
+					chunk_header->chunk_sz, cur_block, crc_ptr);
+			if (ret < 0) {
+				verbose_error(s->verbose, ret, "fill block at %lld", offset);
+				return ret;
+			}
+			return chunk_header->chunk_sz;
+		case CHUNK_TYPE_DONT_CARE:
+			ret = process_skip_chunk(s, chunk_data_size, fd,
+					chunk_header->chunk_sz, cur_block, crc_ptr);
+			if (chunk_data_size != 0) {
+				if (ret < 0) {
+					verbose_error(s->verbose, ret, "skip block at %lld", offset);
+					return ret;
+				}
+			}
+			return chunk_header->chunk_sz;
+		case CHUNK_TYPE_CRC32:
+			ret = process_crc32_chunk(fd, chunk_data_size, *crc_ptr);
+			if (ret < 0) {
+				verbose_error(s->verbose, -EINVAL, "crc block at %lld",
+						offset);
+				return ret;
+			}
+			return 0;
+		default:
+			verbose_error(s->verbose, -EINVAL, "unknown block %04X at %lld",
+					chunk_header->chunk_type, offset);
+	}
+
+	return 0;
+}
+
+static int sparse_file_read_sparse(struct sparse_file *s, int fd, bool crc)
+{
+	int ret;
+	unsigned int i;
+	sparse_header_t sparse_header;
+	chunk_header_t chunk_header;
+	uint32_t crc32 = 0;
+	uint32_t *crc_ptr = 0;
+	unsigned int cur_block = 0;
+	off64_t offset;
+
+	if (!copybuf) {
+		copybuf = malloc(COPY_BUF_SIZE);
+	}
+
+	if (!copybuf) {
+		return -ENOMEM;
+	}
+
+	if (crc) {
+		crc_ptr = &crc32;
+	}
+
+	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
+	if (ret < 0) {
+		return ret;
+	}
+
+	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
+		return -EINVAL;
+	}
+
+	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
+		return -EINVAL;
+	}
+
+	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
+		return -EINVAL;
+	}
+
+	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header)) {
+		return -EINVAL;
+	}
+
+	if (sparse_header.file_hdr_sz > SPARSE_HEADER_LEN) {
+		/* Skip the remaining bytes in a header that is longer than
+		 * we expected.
+		 */
+		lseek64(fd, sparse_header.file_hdr_sz - SPARSE_HEADER_LEN, SEEK_CUR);
+	}
+
+	for (i = 0; i < sparse_header.total_chunks; i++) {
+		ret = read_all(fd, &chunk_header, sizeof(chunk_header));
+		if (ret < 0) {
+			return ret;
+		}
+
+		if (sparse_header.chunk_hdr_sz > CHUNK_HEADER_LEN) {
+			/* Skip the remaining bytes in a header that is longer than
+			 * we expected.
+			 */
+			lseek64(fd, sparse_header.chunk_hdr_sz - CHUNK_HEADER_LEN, SEEK_CUR);
+		}
+
+		offset = lseek64(fd, 0, SEEK_CUR);
+
+		ret = process_chunk(s, fd, offset, sparse_header.chunk_hdr_sz, &chunk_header,
+				cur_block, crc_ptr);
+		if (ret < 0) {
+			return ret;
+		}
+
+		cur_block += ret;
+	}
+
+	if (sparse_header.total_blks != cur_block) {
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int sparse_file_read_normal(struct sparse_file *s, int fd)
+{
+	int ret;
+	uint32_t *buf = malloc(s->block_size);
+	unsigned int block = 0;
+	int64_t remain = s->len;
+	int64_t offset = 0;
+	unsigned int to_read;
+	unsigned int i;
+	bool sparse_block;
+
+	if (!buf) {
+		return -ENOMEM;
+	}
+
+	while (remain > 0) {
+		to_read = min(remain, s->block_size);
+		ret = read_all(fd, buf, to_read);
+		if (ret < 0) {
+			error("failed to read sparse file");
+			return ret;
+		}
+
+		if (to_read == s->block_size) {
+			sparse_block = true;
+			for (i = 1; i < s->block_size / sizeof(uint32_t); i++) {
+				if (buf[0] != buf[i]) {
+					sparse_block = false;
+					break;
+				}
+			}
+		} else {
+			sparse_block = false;
+		}
+
+		if (sparse_block) {
+			/* TODO: add flag to use skip instead of fill for buf[0] == 0 */
+			sparse_file_add_fill(s, buf[0], to_read, block);
+		} else {
+			sparse_file_add_fd(s, fd, offset, to_read, block);
+		}
+
+		remain -= to_read;
+		offset += to_read;
+		block++;
+	}
+
+	return 0;
+}
+
+int sparse_file_read(struct sparse_file *s, int fd, bool sparse, bool crc)
+{
+	if (crc && !sparse) {
+		return -EINVAL;
+	}
+
+	if (sparse) {
+		return sparse_file_read_sparse(s, fd, crc);
+	} else {
+		return sparse_file_read_normal(s, fd);
+	}
+}
+
+struct sparse_file *sparse_file_import(int fd, bool verbose, bool crc)
+{
+	int ret;
+	sparse_header_t sparse_header;
+	int64_t len;
+	struct sparse_file *s;
+
+	ret = read_all(fd, &sparse_header, sizeof(sparse_header));
+	if (ret < 0) {
+		verbose_error(verbose, ret, "header");
+		return NULL;
+	}
+
+	if (sparse_header.magic != SPARSE_HEADER_MAGIC) {
+		verbose_error(verbose, -EINVAL, "header magic");
+		return NULL;
+	}
+
+	if (sparse_header.major_version != SPARSE_HEADER_MAJOR_VER) {
+		verbose_error(verbose, -EINVAL, "header major version");
+		return NULL;
+	}
+
+	if (sparse_header.file_hdr_sz < SPARSE_HEADER_LEN) {
+		return NULL;
+	}
+
+	if (sparse_header.chunk_hdr_sz < sizeof(chunk_header_t)) {
+		return NULL;
+	}
+
+	len = (int64_t)sparse_header.total_blks * sparse_header.blk_sz;
+	s = sparse_file_new(sparse_header.blk_sz, len);
+	if (!s) {
+		verbose_error(verbose, -EINVAL, NULL);
+		return NULL;
+	}
+
+	ret = lseek64(fd, 0, SEEK_SET);
+	if (ret < 0) {
+		verbose_error(verbose, ret, "seeking");
+		sparse_file_destroy(s);
+		return NULL;
+	}
+
+	s->verbose = verbose;
+
+	ret = sparse_file_read(s, fd, true, crc);
+	if (ret < 0) {
+		sparse_file_destroy(s);
+		return NULL;
+	}
+
+	return s;
+}
+
+struct sparse_file *sparse_file_import_auto(int fd, bool crc)
+{
+	struct sparse_file *s;
+	int64_t len;
+	int ret;
+
+	s = sparse_file_import(fd, true, crc);
+	if (s) {
+		return s;
+	}
+
+	len = lseek64(fd, 0, SEEK_END);
+	if (len < 0) {
+		return NULL;
+	}
+
+	lseek64(fd, 0, SEEK_SET);
+
+	s = sparse_file_new(4096, len);
+	if (!s) {
+		return NULL;
+	}
+
+	ret = sparse_file_read_normal(s, fd);
+	if (ret < 0) {
+		sparse_file_destroy(s);
+		return NULL;
+	}
+
+	return s;
+}
diff --git a/distrib/zlib-1.2.8/sources.make b/distrib/zlib-1.2.8/sources.make
index 75b5172..fcd9482 100644
--- a/distrib/zlib-1.2.8/sources.make
+++ b/distrib/zlib-1.2.8/sources.make
@@ -1,4 +1,6 @@
-# this is included by various Makefiles
+OLD_LOCAL_PATH := $(LOCAL_PATH)
+LOCAL_PATH := $(call my-dir)
+
 ZLIB_SOURCES := \
     adler32.c \
     compress.c \
@@ -16,5 +18,16 @@
     uncompr.c \
     zutil.c
 
-ZLIB_SOURCES := $(ZLIB_SOURCES:%=$(ZLIB_DIR)/%)
+ZLIB_INCLUDES := $(LOCAL_PATH)
 
+$(call start-emulator-library,emulator-zlib)
+LOCAL_SRC_FILES := $(ZLIB_SOURCES)
+LOCAL_C_INCLUDES := $(ZLIB_INCLUDES)
+$(call end-emulator-library)
+
+$(call start-emulator64-library,emulator64-zlib)
+LOCAL_SRC_FILES := $(ZLIB_SOURCES)
+LOCAL_C_INCLUDES := $(ZLIB_INCLUDES)
+$(call end-emulator-library)
+
+LOCAL_PATH := $(OLD_LOCAL_PATH)
diff --git a/vl-android.c b/vl-android.c
index 09e4091..e8a3779 100644
--- a/vl-android.c
+++ b/vl-android.c
@@ -54,6 +54,7 @@
 #include "android/log-rotate.h"
 #include "modem_driver.h"
 #include "android/filesystems/ext4_utils.h"
+#include "android/filesystems/partition_types.h"
 #include "android/gps.h"
 #include "android/hw-kmsg.h"
 #include "android/hw-pipe-net.h"
@@ -1866,6 +1867,192 @@
     return -1;  /* shouldn't happen */
 }
 
+
+// Add a NAND partition image to the hardware configuration.
+// |part_name| is a string indicating the type of partition, i.e. "system",
+// "userdata" or "cache".
+// |part_type| is an enum describing the type of partition. If it is
+// DISK_PARTITION_TYPE_PROBE, then try to auto-detect the type directly
+// from the content of |part_file| or |part_init_file|.
+// |part_size| is the partition size in bytes.
+// |part_file| is the partition file path, can be NULL if |path_init_file|
+// is not NULL.
+// |part_init_file| is an optional path to the initialization partition file.
+// |is_ext4| is true if the partition is formatted as EXT4, false for YAFFS2.
+//
+// The NAND partition will be backed by |path_file|, except in the following
+// cases:
+//    - |part_file| is NULL, or its value is "<temp>", indicating that a
+//      new temporary image file must be used instead.
+//
+//    - |part_file| is not NULL, but the function fails to lock the file,
+//      indicating it's already used by another instance. A warning should
+//      be printed to warn the user, and a new temporary image should be
+//      used.
+//
+// If |part_file| is not NULL and can be locked, if the partition image does
+// not exit, then the file must be created as an empty partition.
+//
+// When a new partition image is created, what happens depends on the
+// value of |is_ext4|:
+//
+//    - If |is_ext4| is false, a simple empty file is created, since that's
+//      enough to create an empty YAFFS2 partition.
+//
+//    - If |is_ext4| is true, an "empty ext4" partition image is created
+//      instead, which will _not_ be backed by an empty file.
+//
+// If |part_init_file| is not NULL, its content will be used to erase
+// the content of the main partition image. This is automatically handled
+// by the NAND code though.
+//
+void android_nand_add_image(const char* part_name,
+                            AndroidPartitionType part_type,
+                            uint64_t part_size,
+                            const char* part_file,
+                            const char* part_init_file)
+{
+    char tmp[PATH_MAX * 2 + 32];
+
+    // Sanitize parameters, an empty string must be the same as NULL.
+    if (part_file && !*part_file) {
+        part_file = NULL;
+    }
+    if (part_init_file && !*part_init_file) {
+        part_init_file = NULL;
+    }
+
+    // Sanity checks.
+    if (part_size == 0) {
+        PANIC("Invalid %s partition size 0x%" PRIx64, part_size);
+    }
+
+    if (part_init_file && !path_exists(part_init_file)) {
+        PANIC("Missing initial %s image: %s", part_name, part_init_file);
+    }
+
+    // As a special case, a |part_file| of '<temp>' means a temporary
+    // partition is needed.
+    if (part_file && !strcmp(part_file, "<temp>")) {
+        part_file = NULL;
+    }
+
+    // Verify partition type, or probe it if needed.
+    {
+        const char* image_file = NULL;
+        if (part_init_file && path_exists(part_init_file)) {
+            image_file = part_init_file;
+        } else if (part_file && path_exists(part_file)) {
+            image_file = part_file;
+        }
+
+        if (part_type == ANDROID_PARTITION_TYPE_UNKNOWN) {
+            if (!image_file) {
+                PANIC("Cannot determine type of %s partition: no image files!",
+                    part_name);
+            }
+            VERBOSE_PRINT(init, "Probing %s image file for partition type: %s",
+                        part_name, image_file);
+
+            part_type = androidPartitionType_probeFile(image_file);
+
+            VERBOSE_PRINT(init, "Found %s image format: %s",
+                        part_name, androidPartitionType_toString(part_type));
+        } else {
+            if (!image_file) {
+                PANIC("Cannot find any %s file!", part_name);
+            }
+
+            AndroidPartitionType image_type =
+                    androidPartitionType_probeFile(image_file);
+            if (image_type == ANDROID_PARTITION_TYPE_UNKNOWN) {
+                PANIC("Cannot determine %s partition type of: %s", part_name,
+                    image_file);
+            }
+
+            if (image_type != part_type) {
+                PANIC("Invalid %s partition image type: %s (expected %s)",
+                    part_name,
+                    androidPartitionType_toString(image_type),
+                    androidPartitionType_toString(part_type));
+            }
+        }
+    }
+
+    snprintf(tmp, sizeof tmp, "%s,size=0x%" PRIx64, part_name, part_size);
+
+    bool need_temp_partition = true;
+    bool need_make_empty = false;
+
+    if (part_file && *part_file) {
+        if (filelock_create(part_file) == NULL) {
+            fprintf(stderr,
+                    "WARNING: %s image already in use, changes will not persist!\n",
+                    part_name);
+        } else {
+            need_temp_partition = false;
+
+            if (!path_exists(part_file) && !part_init_file) {
+                need_make_empty = true;
+            }
+        }
+    }
+
+    // Do we need a temporary partition image ?
+    if (need_temp_partition) {
+        TempFile* temp_file = tempfile_create();
+        if (temp_file == NULL) {
+            PANIC("Could not create temp file for %s partition image: %s\n",
+                   part_name);
+        }
+        part_file = tempfile_path(temp_file);
+        VERBOSE_PRINT(init,
+                      "Mapping '%s' partition image to %s",
+                      part_name,
+                      part_file);
+
+        need_make_empty = true;
+    }
+
+    pstrcat(tmp, sizeof tmp, ",file=");
+    pstrcat(tmp, sizeof tmp, part_file);
+
+    // Do we need to make the partition image empty?
+    if (need_make_empty && !part_init_file) {
+        int ret = androidPartitionType_makeEmptyFile(part_type,
+                                                     part_size,
+                                                     part_file);
+        if (ret < 0) {
+            PANIC("Could not create %s image file at %s: %s",
+                  part_name,
+                  part_file,
+                  strerror(-ret));
+        }
+    }
+
+    if (part_init_file) {
+        if (!path_exists(part_init_file)) {
+            PANIC("Invalid initial %s image path: %s",
+                  part_name,
+                  part_init_file);
+        }
+        pstrcat(tmp, sizeof tmp, ",initfile=");
+        pstrcat(tmp, sizeof tmp, part_init_file);
+    }
+
+    if (part_type == ANDROID_PARTITION_TYPE_EXT4) {
+        // Using a nand device to approximate a block device until full
+        // support is added.
+        pstrcat(tmp, sizeof tmp,",pagesize=512,extrasize=0");
+    }
+
+    VERBOSE_PRINT(init, "%s partition format: %s", part_name,
+                  androidPartitionType_toString(part_type));
+
+    nand_add_dev(tmp);
+}
+
+
 int main(int argc, char **argv, char **envp)
 {
     const char *gdbstub_dev = NULL;
@@ -2852,100 +3039,35 @@
         }
     }
 
-    bool systemImageIsExt4 = false;
-    bool dataImageIsExt4 = false;
-    bool cacheImageIsExt4 = false;
-
     /* Initialize system partition image */
-    {
-        char        tmp[PATH_MAX+32];
-        const char* sysImage = android_hw->disk_systemPartition_path;
-        const char* initImage = android_hw->disk_systemPartition_initPath;
-        uint64_t    sysBytes = android_hw->disk_systemPartition_size;
-
-        if (sysBytes == 0) {
-            PANIC("Invalid system partition size: %" PRIu64, sysBytes);
-        }
-
-        snprintf(tmp,sizeof(tmp),"system,size=0x%" PRIx64, sysBytes);
-
-        const char* imageFile = NULL;
-        if (sysImage && *sysImage) {
-            imageFile = sysImage;
-            if (filelock_create(sysImage) == NULL) {
-                fprintf(stderr,"WARNING: System image already in use, changes will not persist!\n");
-                /* If there is no file= parameters, nand_add_dev will create
-                 * a temporary file to back the partition image. */
-            } else {
-                pstrcat(tmp,sizeof(tmp),",file=");
-                pstrcat(tmp,sizeof(tmp),sysImage);
-            }
-        }
-        if (initImage && *initImage) {
-            imageFile = initImage;
-            if (!path_exists(initImage)) {
-                PANIC("Invalid initial system image path: %s", initImage);
-            }
-            pstrcat(tmp,sizeof(tmp),",initfile=");
-            pstrcat(tmp,sizeof(tmp),initImage);
-        } else {
-            PANIC("Missing initial system image path!");
-        }
-        systemImageIsExt4 = imageFile && android_pathIsExt4PartitionImage(imageFile);
-        if (systemImageIsExt4) {
-            /* Using a nand device to approximate a block device until full
-             * support is added */
-            pstrcat(tmp,sizeof(tmp),",pagesize=512,extrasize=0");
-        }
-        VERBOSE_PRINT(init, "System partition format: %s",
-               systemImageIsExt4 ? "ext4" : "yaffs2");
-        nand_add_dev(tmp);
-    }
+    android_nand_add_image("system",
+                            ANDROID_PARTITION_TYPE_UNKNOWN,
+                            android_hw->disk_systemPartition_size,
+                            android_hw->disk_systemPartition_path,
+                            android_hw->disk_systemPartition_initPath);
 
     /* Initialize data partition image */
-    {
-        char        tmp[PATH_MAX+32];
-        const char* dataImage = android_hw->disk_dataPartition_path;
-        const char* initImage = android_hw->disk_dataPartition_initPath;
-        uint64_t    dataBytes = android_hw->disk_dataPartition_size;
+    android_nand_add_image("userdata",
+                            ANDROID_PARTITION_TYPE_UNKNOWN,
+                            android_hw->disk_dataPartition_size,
+                            android_hw->disk_dataPartition_path,
+                            android_hw->disk_dataPartition_initPath);
 
-        if (dataBytes == 0) {
-            PANIC("Invalid data partition size: %" PRIu64, dataBytes);
-        }
+    /* Initialize cache partition image, if any. Its type depends on the
+     * kernel version. For anything >= 3.10, it must be EXT4, or
+     * YAFFS2 otherwise.
+     */
+    if (android_hw->disk_cachePartition != 0) {
+        AndroidPartitionType cache_part_type =
+                (androidHwConfig_getKernelYaffs2Support(android_hw) >= 1) ?
+                        ANDROID_PARTITION_TYPE_YAFFS2 :
+                        ANDROID_PARTITION_TYPE_EXT4;
 
-        snprintf(tmp,sizeof(tmp),"userdata,size=0x%" PRIx64, dataBytes);
-
-        const char* imageFile = dataImage;
-        if (dataImage && *dataImage) {
-            if (filelock_create(dataImage) == NULL) {
-                fprintf(stderr, "WARNING: Data partition already in use. Changes will not persist!\n");
-                /* Note: if there is no file= parameters, nand_add_dev() will
-                 *       create a temporary file to back the partition image. */
-            } else {
-                /* Create the file if needed */
-                if (!path_exists(dataImage)) {
-                    if (path_empty_file(dataImage) < 0) {
-                        PANIC("Could not create data image file %s: %s", dataImage, strerror(errno));
-                    }
-                }
-                pstrcat(tmp, sizeof(tmp), ",file=");
-                pstrcat(tmp, sizeof(tmp), dataImage);
-            }
-        }
-        if (initImage && *initImage) {
-            imageFile = initImage;
-            pstrcat(tmp, sizeof(tmp), ",initfile=");
-            pstrcat(tmp, sizeof(tmp), initImage);
-        }
-        dataImageIsExt4 = imageFile && android_pathIsExt4PartitionImage(imageFile);
-        if (dataImageIsExt4) {
-            /* Using a nand device to approximate a block device until full
-             * support is added */
-            pstrcat(tmp, sizeof(tmp), ",pagesize=512,extrasize=0");
-        }
-        VERBOSE_PRINT(init, "Data partition format: %s",
-               dataImageIsExt4 ? "ext4" : "yaffs2");
-        nand_add_dev(tmp);
+        android_nand_add_image("cache",
+                                cache_part_type,
+                                android_hw->disk_cachePartition_size,
+                                android_hw->disk_cachePartition_path,
+                                NULL);
     }
 
     /* Init SD-Card stuff. For Android, it is always hda */
@@ -3162,49 +3284,6 @@
     }
 #endif  // CONFIG_ANDROID_MEMCHECK
 
-    /* Initialize cache partition, if any */
-    if (android_hw->disk_cachePartition != 0) {
-        char        tmp[PATH_MAX+32];
-        const char* partPath = android_hw->disk_cachePartition_path;
-        uint64_t    partSize = android_hw->disk_cachePartition_size;
-
-        snprintf(tmp,sizeof(tmp),"cache,size=0x%" PRIx64, partSize);
-
-        if (partPath && *partPath && strcmp(partPath, "<temp>") != 0) {
-            if (filelock_create(partPath) == NULL) {
-                fprintf(stderr, "WARNING: Cache partition already in use. Changes will not persist!\n");
-                /* Note: if there is no file= parameters, nand_add_dev() will
-                 *       create a temporary file to back the partition image. */
-            } else {
-                /* Create the file if needed */
-                if (!path_exists(partPath)) {
-                    // TODO(digit): For EXT4, create a real empty ext4 partition image.
-                    if (path_empty_file(partPath) < 0) {
-                        PANIC("Could not create cache image file %s: %s", partPath, strerror(errno));
-                    }
-                }
-                pstrcat(tmp, sizeof(tmp), ",file=");
-                pstrcat(tmp, sizeof(tmp), partPath);
-            }
-        }
-        // NOTE: The following line is commented to avoid problems with the
-        // current state of the emulator and AOSP/master. In a nutshell,
-        // take it out of the comment once proper support for generating
-        // EXT4 partitions on demand is added to the emulator, and
-        //  /etc/fstab.goldfish is modified to mount an EXT4, not YAFFS2,
-        // partition for /cache.
-        //
-        // cacheImageIsExt4 = partPath && android_pathIsExt4PartitionImage(partPath);
-        if (cacheImageIsExt4) {
-            /* Using a nand device to approximate a block device until full
-             * support is added */
-            pstrcat(tmp, sizeof(tmp), ",pagesize=512,extrasize=0");
-        }
-        VERBOSE_PRINT(init, "Cache partition format: %s",
-               cacheImageIsExt4 ? "ext4" : "yaffs2");
-        nand_add_dev(tmp);
-    }
-
     /* qemu.gles will be read by the OpenGL ES emulation libraries.
      * If set to 0, the software GL ES renderer will be used as a fallback.
      * If the parameter is undefined, this means the system image runs