Merge commit 'e2d1d99f1a98b02a28fe71f2a387a72b69d4b4a6' from
oc-mr1-dev-plus-aosp into stage-aosp-master

Change-Id: I4bdada4c933109f1cc60c61946fa30e174ca7583
diff --git a/Android.mk b/Android.mk
index 8004fc3..bd457f6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,6 +26,7 @@
 	MoveTask.cpp \
 	Benchmark.cpp \
 	TrimTask.cpp \
+	KeyBuffer.cpp \
 	Keymaster.cpp \
 	KeyStorage.cpp \
 	KeyUtil.cpp \
@@ -86,6 +87,8 @@
     vold_cflags += -DTARGET_USES_MKE2FS
     required_modules += mke2fs
   else
+    # Adoptable storage has fully moved to mke2fs, so we need both tools
+    required_modules += mke2fs
     required_modules += make_ext4fs
   endif
 endif
@@ -156,7 +159,10 @@
 LOCAL_TIDY := true
 LOCAL_TIDY_FLAGS := $(common_local_tidy_flags)
 LOCAL_TIDY_CHECKS := $(common_local_tidy_checks)
-LOCAL_SRC_FILES:= secdiscard.cpp
+LOCAL_SRC_FILES:= \
+    FileDeviceUtils.cpp \
+    secdiscard.cpp \
+
 LOCAL_MODULE:= secdiscard
 LOCAL_SHARED_LIBRARIES := libbase
 LOCAL_CFLAGS := $(vold_cflags)
diff --git a/AutoCloseFD.h b/AutoCloseFD.h
deleted file mode 100644
index 9b68469..0000000
--- a/AutoCloseFD.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2015 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>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <android-base/logging.h>
-
-// File descriptor which is automatically closed when this object is destroyed.
-// Cannot be copied, since that would cause double-closes.
-class AutoCloseFD {
-public:
-    AutoCloseFD(const char *path, int flags = O_RDONLY, int mode = 0):
-        fd{TEMP_FAILURE_RETRY(open(path, flags | O_CLOEXEC, mode))} {}
-    AutoCloseFD(const std::string &path, int flags = O_RDONLY, int mode = 0):
-        AutoCloseFD(path.c_str(), flags, mode) {}
-    ~AutoCloseFD() {
-        if (fd != -1) {
-            int preserve_errno = errno;
-            if (close(fd) == -1) {
-                PLOG(ERROR) << "close(2) failed";
-            };
-            errno = preserve_errno;
-        }
-    }
-    AutoCloseFD(const AutoCloseFD&) = delete;
-    AutoCloseFD& operator=(const AutoCloseFD&) = delete;
-    explicit operator bool() {return fd != -1;}
-    int get() const {return fd;}
-private:
-    const int fd;
-};
-
diff --git a/Disk.cpp b/Disk.cpp
index b424aba..9c22400 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -24,6 +24,7 @@
 #include "Ext4Crypt.h"
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android-base/logging.h>
 #include <diskconfig/diskconfig.h>
@@ -446,7 +447,8 @@
 status_t Disk::partitionMixed(int8_t ratio) {
     int res;
 
-    if (e4crypt_is_native()) {
+    if (e4crypt_is_native()
+            && !android::base::GetBoolProperty("persist.sys.adoptable_fbe", false)) {
         LOG(ERROR) << "Private volumes not yet supported on FBE devices";
         return -EINVAL;
     }
@@ -469,9 +471,14 @@
     // We've had some success above, so generate both the private partition
     // GUID and encryption key and persist them.
     std::string partGuidRaw;
+    if (GenerateRandomUuid(partGuidRaw) != OK) {
+        LOG(ERROR) << "Failed to generate GUID";
+        return -EIO;
+    }
+
     std::string keyRaw;
-    if (ReadRandomBytes(16, partGuidRaw) || ReadRandomBytes(16, keyRaw)) {
-        LOG(ERROR) << "Failed to generate GUID or key";
+    if (ReadRandomBytes(16, keyRaw) != OK) {
+        LOG(ERROR) << "Failed to generate key";
         return -EIO;
     }
 
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index 44ad22a..21b290a 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -84,6 +84,7 @@
                 "-g", "1023", // AID_MEDIA_RW
                 "-m",
                 "-w",
+                "-G",
                 mRawPath.c_str(),
                 label.c_str(),
                 NULL)) {
@@ -103,6 +104,8 @@
         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
         usleep(50000); // 50ms
     }
+    /* sdcardfs will have exited already. FUSE will still be running */
+    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
 
     return OK;
 }
diff --git a/Ext4Crypt.cpp b/Ext4Crypt.cpp
index c3e0cc3..dc2e42a 100644
--- a/Ext4Crypt.cpp
+++ b/Ext4Crypt.cpp
@@ -30,6 +30,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <limits.h>
 #include <selinux/android.h>
 #include <sys/mount.h>
@@ -54,7 +55,9 @@
 #include <android-base/stringprintf.h>
 
 using android::base::StringPrintf;
+using android::base::WriteStringToFile;
 using android::vold::kEmptyAuthentication;
+using android::vold::KeyBuffer;
 
 // NOTE: keep in sync with StorageManager
 static constexpr int FLAG_STORAGE_DE = 1 << 0;
@@ -78,7 +81,7 @@
 std::map<userid_t, std::string> s_de_key_raw_refs;
 std::map<userid_t, std::string> s_ce_key_raw_refs;
 // TODO abolish this map, per b/26948053
-std::map<userid_t, std::string> s_ce_keys;
+std::map<userid_t, KeyBuffer> s_ce_keys;
 
 }
 
@@ -168,7 +171,7 @@
 
 static bool read_and_fixate_user_ce_key(userid_t user_id,
                                         const android::vold::KeyAuthentication& auth,
-                                        std::string *ce_key) {
+                                        KeyBuffer *ce_key) {
     auto const directory_path = get_ce_key_directory_path(user_id);
     auto const paths = get_ce_key_paths(directory_path);
     for (auto const ce_key_path: paths) {
@@ -186,11 +189,11 @@
 static bool read_and_install_user_ce_key(userid_t user_id,
                                          const android::vold::KeyAuthentication& auth) {
     if (s_ce_key_raw_refs.count(user_id) != 0) return true;
-    std::string ce_key;
+    KeyBuffer ce_key;
     if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false;
     std::string ce_raw_ref;
     if (!android::vold::installKey(ce_key, &ce_raw_ref)) return false;
-    s_ce_keys[user_id] = ce_key;
+    s_ce_keys[user_id] = std::move(ce_key);
     s_ce_key_raw_refs[user_id] = ce_raw_ref;
     LOG(DEBUG) << "Installed ce key for user " << user_id;
     return true;
@@ -217,7 +220,7 @@
 // NB this assumes that there is only one thread listening for crypt commands, because
 // it creates keys in a fixed location.
 static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral) {
-    std::string de_key, ce_key;
+    KeyBuffer de_key, ce_key;
     if (!android::vold::randomKey(&de_key)) return false;
     if (!android::vold::randomKey(&ce_key)) return false;
     if (create_ephemeral) {
@@ -304,7 +307,7 @@
         userid_t user_id = atoi(entry->d_name);
         if (s_de_key_raw_refs.count(user_id) == 0) {
             auto key_path = de_dir + "/" + entry->d_name;
-            std::string key;
+            KeyBuffer key;
             if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
             std::string raw_ref;
             if (!android::vold::installKey(key, &raw_ref)) return false;
@@ -399,13 +402,23 @@
     return true;
 }
 
+static void drop_caches() {
+    // Clean any dirty pages (otherwise they won't be dropped).
+    sync();
+    // Drop inode and page caches.
+    if (!WriteStringToFile("3", "/proc/sys/vm/drop_caches")) {
+        PLOG(ERROR) << "Failed to drop caches during key eviction";
+    }
+}
+
 static bool evict_ce_key(userid_t user_id) {
-   s_ce_keys.erase(user_id);
+    s_ce_keys.erase(user_id);
     bool success = true;
     std::string raw_ref;
     // If we haven't loaded the CE key, no need to evict it.
     if (lookup_key_ref(s_ce_key_raw_refs, user_id, &raw_ref)) {
         success &= android::vold::evictKey(raw_ref);
+        drop_caches();
     }
     s_ce_key_raw_refs.erase(user_id);
     return success;
@@ -497,7 +510,7 @@
         LOG(ERROR) << "Key not loaded into memory, can't change for user " << user_id;
         return false;
     }
-    auto ce_key = it->second;
+    const auto &ce_key = it->second;
     auto const directory_path = get_ce_key_directory_path(user_id);
     auto const paths = get_ce_key_paths(directory_path);
     std::string ce_key_path;
@@ -599,8 +612,7 @@
         if (!prepare_dir(misc_de_path, 01771, AID_SYSTEM, AID_MISC)) return false;
         if (!prepare_dir(user_de_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        // For now, FBE is only supported on internal storage
-        if (e4crypt_is_native() && volume_uuid == nullptr) {
+        if (e4crypt_is_native()) {
             std::string de_raw_ref;
             if (!lookup_key_ref(s_de_key_raw_refs, user_id, &de_raw_ref)) return false;
             if (!ensure_policy(de_raw_ref, system_de_path)) return false;
@@ -621,8 +633,7 @@
         if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false;
         if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false;
 
-        // For now, FBE is only supported on internal storage
-        if (e4crypt_is_native() && volume_uuid == nullptr) {
+        if (e4crypt_is_native()) {
             std::string ce_raw_ref;
             if (!lookup_key_ref(s_ce_key_raw_refs, user_id, &ce_raw_ref)) return false;
             if (!ensure_policy(ce_raw_ref, system_ce_path)) return false;
diff --git a/FileDeviceUtils.cpp b/FileDeviceUtils.cpp
new file mode 100644
index 0000000..bc9f4bd
--- /dev/null
+++ b/FileDeviceUtils.cpp
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2017 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 "FileDeviceUtils.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+#include <mntent.h>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+
+namespace {
+
+std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
+
+}
+
+namespace android {
+namespace vold {
+
+// Given a file path, look for the corresponding block device in /proc/mount
+std::string BlockDeviceForPath(const std::string &path)
+{
+    std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
+    if (!mnts) {
+        PLOG(ERROR) << "Unable to open /proc/mounts";
+        return "";
+    }
+    std::string result;
+    size_t best_length = 0;
+    struct mntent *mnt; // getmntent returns a thread local, so it's safe.
+    while ((mnt = getmntent(mnts.get())) != nullptr) {
+        auto l = strlen(mnt->mnt_dir);
+        if (l > best_length &&
+            path.size() > l &&
+            path[l] == '/' &&
+            path.compare(0, l, mnt->mnt_dir) == 0) {
+                result = mnt->mnt_fsname;
+                best_length = l;
+        }
+    }
+    if (result.empty()) {
+        LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
+        return "";
+    }
+    LOG(DEBUG) << "For path " << path << " block device is " << result;
+    return result;
+}
+
+std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count)
+{
+    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(
+        path.c_str(), O_RDONLY | O_CLOEXEC, 0)));
+    if (fd == -1) {
+        if (errno == ENOENT) {
+            PLOG(DEBUG) << "Unable to open " << path;
+        } else {
+            PLOG(ERROR) << "Unable to open " << path;
+        }
+        return nullptr;
+    }
+    auto fiemap = alloc_fiemap(extent_count);
+    if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
+        PLOG(ERROR) << "Unable to FIEMAP " << path;
+        return nullptr;
+    }
+    auto mapped = fiemap->fm_mapped_extents;
+    if (mapped < 1 || mapped > extent_count) {
+        LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
+            << " in " << path;
+        return nullptr;
+    }
+    return fiemap;
+}
+
+}  // namespace vold
+}  // namespace android
+
+namespace {
+
+std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
+{
+    size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
+    std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
+    memset(res.get(), 0, allocsize);
+    res->fm_start = 0;
+    res->fm_length = UINT64_MAX;
+    res->fm_flags = 0;
+    res->fm_extent_count = extent_count;
+    res->fm_mapped_extents = 0;
+    return res;
+}
+
+}
diff --git a/FileDeviceUtils.h b/FileDeviceUtils.h
new file mode 100644
index 0000000..4c1d49a
--- /dev/null
+++ b/FileDeviceUtils.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_VOLD_FILEDEVICEUTILS_H
+#define ANDROID_VOLD_FILEDEVICEUTILS_H
+
+#include <string>
+#include <linux/fiemap.h>
+
+namespace android {
+namespace vold {
+
+// Given a file path, look for the corresponding block device in /proc/mount
+std::string BlockDeviceForPath(const std::string &path);
+
+// Read the file's FIEMAP
+std::unique_ptr<struct fiemap> PathFiemap(const std::string &path, uint32_t extent_count);
+
+}  // namespace vold
+}  // namespace android
+
+#endif
diff --git a/KeyBuffer.cpp b/KeyBuffer.cpp
new file mode 100644
index 0000000..e7aede5
--- /dev/null
+++ b/KeyBuffer.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 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 "KeyBuffer.h"
+
+#include <algorithm>
+#include <cstring>
+
+namespace android {
+namespace vold {
+
+KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs) {
+    std::copy(rhs.begin(), rhs.end(), std::back_inserter(lhs));
+    return std::move(lhs);
+}
+
+KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs) {
+    std::copy(rhs, rhs + strlen(rhs), std::back_inserter(lhs));
+    return std::move(lhs);
+}
+
+}  // namespace vold
+}  // namespace android
+
diff --git a/KeyBuffer.h b/KeyBuffer.h
new file mode 100644
index 0000000..2087187
--- /dev/null
+++ b/KeyBuffer.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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 ANDROID_VOLD_KEYBUFFER_H
+#define ANDROID_VOLD_KEYBUFFER_H
+
+#include <cstring>
+#include <memory>
+#include <vector>
+
+namespace android {
+namespace vold {
+
+/**
+ * Variant of memset() that should never be optimized away. Borrowed from keymaster code.
+ */
+#ifdef __clang__
+#define OPTNONE __attribute__((optnone))
+#else  // not __clang__
+#define OPTNONE __attribute__((optimize("O0")))
+#endif  // not __clang__
+inline OPTNONE void* memset_s(void* s, int c, size_t n) {
+    if (!s)
+        return s;
+    return memset(s, c, n);
+}
+#undef OPTNONE
+
+// Allocator that delegates useful work to standard one but zeroes data before deallocating.
+class ZeroingAllocator : public std::allocator<char> {
+    public:
+    void deallocate(pointer p, size_type n)
+    {
+        memset_s(p, 0, n);
+        std::allocator<char>::deallocate(p, n);
+    }
+};
+
+// Char vector that zeroes memory when deallocating.
+using KeyBuffer = std::vector<char, ZeroingAllocator>;
+
+// Convenience methods to concatenate key buffers.
+KeyBuffer operator+(KeyBuffer&& lhs, const KeyBuffer& rhs);
+KeyBuffer operator+(KeyBuffer&& lhs, const char* rhs);
+
+}  // namespace vold
+}  // namespace android
+
+#endif
+
diff --git a/KeyStorage.cpp b/KeyStorage.cpp
index b4f85f4..9d61555 100644
--- a/KeyStorage.cpp
+++ b/KeyStorage.cpp
@@ -195,7 +195,7 @@
 
 static bool encryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
                                     const AuthorizationSet &keyParams,
-                                    const std::string& message, std::string* ciphertext) {
+                                    const KeyBuffer& message, std::string* ciphertext) {
     AuthorizationSet opParams;
     AuthorizationSet outParams;
     auto opHandle = begin(keymaster, dir, KeyPurpose::ENCRYPT, keyParams, opParams, &outParams);
@@ -220,7 +220,7 @@
 
 static bool decryptWithKeymasterKey(Keymaster& keymaster, const std::string& dir,
                                     const AuthorizationSet &keyParams,
-                                    const std::string& ciphertext, std::string* message) {
+                                    const std::string& ciphertext, KeyBuffer* message) {
     auto nonce = ciphertext.substr(0, GCM_NONCE_BYTES);
     auto bodyAndMac = ciphertext.substr(GCM_NONCE_BYTES);
     auto opParams = AuthorizationSetBuilder()
@@ -305,7 +305,7 @@
 }
 
 static bool encryptWithoutKeymaster(const std::string& preKey,
-                                    const std::string& plaintext, std::string* ciphertext) {
+                                    const KeyBuffer& plaintext, std::string* ciphertext) {
     auto key = hashWithPrefix(kHashPrefix_keygen, preKey);
     key.resize(AES_KEY_BYTES);
     if (!readRandomBytesOrLog(GCM_NONCE_BYTES, ciphertext)) return false;
@@ -351,7 +351,7 @@
 }
 
 static bool decryptWithoutKeymaster(const std::string& preKey,
-                                    const std::string& ciphertext, std::string* plaintext) {
+                                    const std::string& ciphertext, KeyBuffer* plaintext) {
     if (ciphertext.size() < GCM_NONCE_BYTES + GCM_MAC_BYTES) {
         LOG(ERROR) << "GCM ciphertext too small: " << ciphertext.size();
         return false;
@@ -370,7 +370,7 @@
         logOpensslError();
         return false;
     }
-    plaintext->resize(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
+    *plaintext = KeyBuffer(ciphertext.size() - GCM_NONCE_BYTES - GCM_MAC_BYTES);
     int outlen;
     if (1 != EVP_DecryptUpdate(ctx.get(),
         reinterpret_cast<uint8_t*>(&(*plaintext)[0]), &outlen,
@@ -404,7 +404,7 @@
     return access(path.c_str(), F_OK) == 0;
 }
 
-bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key) {
+bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key) {
     if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), 0700)) == -1) {
         PLOG(ERROR) << "key mkdir " << dir;
         return false;
@@ -442,7 +442,7 @@
 }
 
 bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path,
-                        const KeyAuthentication& auth, const std::string& key) {
+                        const KeyAuthentication& auth, const KeyBuffer& key) {
     if (pathExists(key_path)) {
         LOG(ERROR) << "Already exists, cannot create key at: " << key_path;
         return false;
@@ -460,7 +460,7 @@
     return true;
 }
 
-bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key) {
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key) {
     std::string version;
     if (!readFileToString(dir + "/" + kFn_version, &version)) return false;
     if (version != kCurrentVersion) {
diff --git a/KeyStorage.h b/KeyStorage.h
index 63345f4..655cd17 100644
--- a/KeyStorage.h
+++ b/KeyStorage.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_VOLD_KEYSTORAGE_H
 #define ANDROID_VOLD_KEYSTORAGE_H
 
+#include "KeyBuffer.h"
+
 #include <string>
 
 namespace android {
@@ -46,17 +48,17 @@
 // in such a way that it can only be retrieved via Keymaster and
 // can be securely deleted.
 // It's safe to move/rename the directory after creation.
-bool storeKey(const std::string& dir, const KeyAuthentication& auth, const std::string& key);
+bool storeKey(const std::string& dir, const KeyAuthentication& auth, const KeyBuffer& key);
 
 // Create a directory at the named path, and store "key" in it as storeKey
 // This version creates the key in "tmp_path" then atomically renames "tmp_path"
 // to "key_path" thereby ensuring that the key is either stored entirely or
 // not at all.
 bool storeKeyAtomically(const std::string& key_path, const std::string& tmp_path,
-                        const KeyAuthentication& auth, const std::string& key);
+                        const KeyAuthentication& auth, const KeyBuffer& key);
 
 // Retrieve the key from the named directory.
-bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, std::string* key);
+bool retrieveKey(const std::string& dir, const KeyAuthentication& auth, KeyBuffer* key);
 
 // Securely destroy the key stored in the named directory and delete the directory.
 bool destroyKey(const std::string& dir);
diff --git a/KeyUtil.cpp b/KeyUtil.cpp
index a75dfbb..dbc73c1 100644
--- a/KeyUtil.cpp
+++ b/KeyUtil.cpp
@@ -32,8 +32,23 @@
 namespace android {
 namespace vold {
 
-bool randomKey(std::string* key) {
-    if (ReadRandomBytes(EXT4_AES_256_XTS_KEY_SIZE, *key) != 0) {
+// ext4enc:TODO get this const from somewhere good
+const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
+
+// ext4enc:TODO Include structure from somewhere sensible
+// MUST be in sync with ext4_crypto.c in kernel
+constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
+constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
+constexpr int EXT4_MAX_KEY_SIZE = 64;
+struct ext4_encryption_key {
+    uint32_t mode;
+    char raw[EXT4_MAX_KEY_SIZE];
+    uint32_t size;
+};
+
+bool randomKey(KeyBuffer* key) {
+    *key = KeyBuffer(EXT4_AES_256_XTS_KEY_SIZE);
+    if (ReadRandomBytes(key->size(), key->data()) != 0) {
         // TODO status_t plays badly with PLOG, fix it.
         LOG(ERROR) << "Random read failed";
         return false;
@@ -60,7 +75,7 @@
     return std::string((char*)key_ref2, EXT4_KEY_DESCRIPTOR_SIZE);
 }
 
-static bool fillKey(const std::string& key, ext4_encryption_key* ext4_key) {
+static bool fillKey(const KeyBuffer& key, ext4_encryption_key* ext4_key) {
     if (key.size() != EXT4_AES_256_XTS_KEY_SIZE) {
         LOG(ERROR) << "Wrong size key " << key.size();
         return false;
@@ -83,7 +98,7 @@
 static std::string keyname(const std::string& prefix, const std::string& raw_ref) {
     std::ostringstream o;
     o << prefix << ":";
-    for (auto i : raw_ref) {
+    for (unsigned char i : raw_ref) {
         o << std::hex << std::setw(2) << std::setfill('0') << (int)i;
     }
     return o.str();
@@ -101,8 +116,11 @@
 
 // Install password into global keyring
 // Return raw key reference for use in policy
-bool installKey(const std::string& key, std::string* raw_ref) {
-    ext4_encryption_key ext4_key;
+bool installKey(const KeyBuffer& key, std::string* raw_ref) {
+    // Place ext4_encryption_key into automatically zeroing buffer.
+    KeyBuffer ext4KeyBuffer(sizeof(ext4_encryption_key));
+    ext4_encryption_key &ext4_key = *reinterpret_cast<ext4_encryption_key*>(ext4KeyBuffer.data());
+
     if (!fillKey(key, &ext4_key)) return false;
     *raw_ref = generateKeyRef(ext4_key.raw, ext4_key.size);
     key_serial_t device_keyring;
@@ -145,7 +163,7 @@
 
 bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
                            const std::string& tmp_path, std::string* key_ref) {
-    std::string key;
+    KeyBuffer key;
     if (pathExists(key_path)) {
         LOG(DEBUG) << "Key exists, using: " << key_path;
         if (!retrieveKey(key_path, kEmptyAuthentication, &key)) return false;
@@ -168,7 +186,7 @@
 }
 
 bool retrieveKey(bool create_if_absent, const std::string& key_path,
-                 const std::string& tmp_path, std::string* key) {
+                 const std::string& tmp_path, KeyBuffer* key) {
     if (pathExists(key_path)) {
         LOG(DEBUG) << "Key exists, using: " << key_path;
         if (!retrieveKey(key_path, kEmptyAuthentication, key)) return false;
diff --git a/KeyUtil.h b/KeyUtil.h
index d4c97b9..412b0ae 100644
--- a/KeyUtil.h
+++ b/KeyUtil.h
@@ -17,32 +17,21 @@
 #ifndef ANDROID_VOLD_KEYUTIL_H
 #define ANDROID_VOLD_KEYUTIL_H
 
+#include "KeyBuffer.h"
+
 #include <string>
+#include <memory>
 
 namespace android {
 namespace vold {
 
-// ext4enc:TODO get this const from somewhere good
-const int EXT4_KEY_DESCRIPTOR_SIZE = 8;
-
-// ext4enc:TODO Include structure from somewhere sensible
-// MUST be in sync with ext4_crypto.c in kernel
-constexpr int EXT4_ENCRYPTION_MODE_AES_256_XTS = 1;
-constexpr int EXT4_AES_256_XTS_KEY_SIZE = 64;
-constexpr int EXT4_MAX_KEY_SIZE = 64;
-struct ext4_encryption_key {
-    uint32_t mode;
-    char raw[EXT4_MAX_KEY_SIZE];
-    uint32_t size;
-};
-
-bool randomKey(std::string* key);
-bool installKey(const std::string& key, std::string* raw_ref);
+bool randomKey(KeyBuffer* key);
+bool installKey(const KeyBuffer& key, std::string* raw_ref);
 bool evictKey(const std::string& raw_ref);
 bool retrieveAndInstallKey(bool create_if_absent, const std::string& key_path,
                            const std::string& tmp_path, std::string* key_ref);
 bool retrieveKey(bool create_if_absent, const std::string& key_path,
-                 const std::string& tmp_path, std::string* key);
+                 const std::string& tmp_path, KeyBuffer* key);
 
 }  // namespace vold
 }  // namespace android
diff --git a/Keymaster.cpp b/Keymaster.cpp
index ffa3a7a..1bbeb61 100644
--- a/Keymaster.cpp
+++ b/Keymaster.cpp
@@ -31,25 +31,23 @@
     if (mDevice.get()) mDevice->abort(mOpHandle);
 }
 
-bool KeymasterOperation::updateCompletely(const std::string& input, std::string* output) {
-    if (output)
-        output->clear();
-    auto it = input.begin();
-    uint32_t inputConsumed;
+bool KeymasterOperation::updateCompletely(const char* input, size_t inputLen,
+        const std::function<void(const char*, size_t)> consumer) {
+    uint32_t inputConsumed = 0;
 
     ErrorCode km_error;
-    auto hidlCB = [&] (ErrorCode ret, uint32_t _inputConsumed,
+    auto hidlCB = [&] (ErrorCode ret, uint32_t inputConsumedDelta,
             const hidl_vec<KeyParameter>& /*ignored*/, const hidl_vec<uint8_t>& _output) {
         km_error = ret;
         if (km_error != ErrorCode::OK) return;
-        inputConsumed = _inputConsumed;
-        if (output)
-            output->append(reinterpret_cast<const char*>(&_output[0]), _output.size());
+        inputConsumed += inputConsumedDelta;
+        consumer(reinterpret_cast<const char*>(&_output[0]), _output.size());
     };
 
-    while (it != input.end()) {
-        size_t toRead = static_cast<size_t>(input.end() - it);
-        auto inputBlob = blob2hidlVec(reinterpret_cast<const uint8_t*>(&*it), toRead);
+    while (inputConsumed != inputLen) {
+        size_t toRead = static_cast<size_t>(inputLen - inputConsumed);
+        auto inputBlob =
+                blob2hidlVec(reinterpret_cast<const uint8_t*>(&input[inputConsumed]), toRead);
         auto error = mDevice->update(mOpHandle, hidl_vec<KeyParameter>(), inputBlob, hidlCB);
         if (!error.isOk()) {
             LOG(ERROR) << "update failed: " << error.description();
@@ -61,12 +59,11 @@
             mDevice = nullptr;
             return false;
         }
-        if (inputConsumed > toRead) {
+        if (inputConsumed > inputLen) {
             LOG(ERROR) << "update reported too much input consumed";
             mDevice = nullptr;
             return false;
         }
-        it += inputConsumed;
     }
     return true;
 }
diff --git a/Keymaster.h b/Keymaster.h
index 4bc0df7..dc6f1bc 100644
--- a/Keymaster.h
+++ b/Keymaster.h
@@ -19,6 +19,8 @@
 
 #ifdef __cplusplus
 
+#include "KeyBuffer.h"
+
 #include <memory>
 #include <string>
 #include <utility>
@@ -51,7 +53,14 @@
     ErrorCode errorCode() { return mError; }
     // Call "update" repeatedly until all of the input is consumed, and
     // concatenate the output. Return true on success.
-    bool updateCompletely(const std::string& input, std::string* output);
+    template <class TI, class TO>
+    bool updateCompletely(TI& input, TO* output) {
+        if (output) output->clear();
+        return updateCompletely(input.data(), input.size(), [&](const char* b, size_t n) {
+            if (output) std::copy(b, b+n, std::back_inserter(*output));
+        });
+    }
+
     // Finish and write the output to this string, unless pointer is null.
     bool finish(std::string* output);
     // Move constructor
@@ -80,6 +89,10 @@
     KeymasterOperation(ErrorCode error)
         : mDevice{nullptr}, mOpHandle{0},
           mError {error} {}
+
+    bool updateCompletely(const char* input, size_t inputLen,
+                          const std::function<void(const char*, size_t)> consumer);
+
     sp<IKeymasterDevice> mDevice;
     uint64_t mOpHandle;
     ErrorCode mError;
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index b707549..8311813 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -14,11 +14,13 @@
  * limitations under the License.
  */
 
+#include "KeyBuffer.h"
 #include "MetadataCrypt.h"
 
 #include <string>
 #include <thread>
 #include <vector>
+#include <algorithm>
 
 #include <fcntl.h>
 #include <sys/ioctl.h>
@@ -29,10 +31,10 @@
 #include <linux/dm-ioctl.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 #include <cutils/properties.h>
 #include <fs_mgr.h>
 
-#include "AutoCloseFD.h"
 #include "EncryptInplace.h"
 #include "KeyStorage.h"
 #include "KeyUtil.h"
@@ -45,6 +47,8 @@
 #define TABLE_LOAD_RETRIES 10
 #define DEFAULT_KEY_TARGET_TYPE "default-key"
 
+using android::vold::KeyBuffer;
+
 static const std::string kDmNameUserdata = "userdata";
 
 static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) {
@@ -68,7 +72,7 @@
     return true;
 }
 
-static bool read_key(bool create_if_absent, std::string* key) {
+static bool read_key(bool create_if_absent, KeyBuffer* key) {
     auto data_rec = fs_mgr_get_crypt_entry(fstab);
     if (!data_rec) {
         LOG(ERROR) << "Failed to get data_rec";
@@ -93,20 +97,21 @@
     return true;
 }
 
-static std::string default_key_params(const std::string& real_blkdev, const std::string& key) {
-    std::string hex_key;
+static KeyBuffer default_key_params(const std::string& real_blkdev, const KeyBuffer& key) {
+    KeyBuffer hex_key;
     if (android::vold::StrToHex(key, hex_key) != android::OK) {
         LOG(ERROR) << "Failed to turn key to hex";
-        return "";
+        return KeyBuffer();
     }
-    auto res = std::string() + "AES-256-XTS " + hex_key + " " + real_blkdev + " 0";
-    LOG(DEBUG) << "crypt_params: " << res;
+    auto res = KeyBuffer() + "AES-256-XTS " + hex_key + " " + real_blkdev.c_str() + " 0";
+    LOG(DEBUG) << "crypt_params: " << std::string(res.data(), res.size());
     return res;
 }
 
 static bool get_number_of_sectors(const std::string& real_blkdev, uint64_t *nr_sec) {
-    AutoCloseFD dev_fd(real_blkdev, O_RDONLY);
-    if (!dev_fd) {
+    android::base::unique_fd dev_fd(TEMP_FAILURE_RETRY(open(
+        real_blkdev.c_str(), O_RDONLY | O_CLOEXEC, 0)));
+    if (dev_fd == -1) {
         PLOG(ERROR) << "Unable to open " << real_blkdev << " to measure size";
         return false;
     }
@@ -141,10 +146,11 @@
 }
 
 static bool create_crypto_blk_dev(const std::string& dm_name, uint64_t nr_sec,
-                                  const std::string& target_type, const std::string& crypt_params,
+                                  const std::string& target_type, const KeyBuffer& crypt_params,
                                   std::string* crypto_blkdev) {
-    AutoCloseFD dm_fd("/dev/device-mapper", O_RDWR);
-    if (!dm_fd) {
+    android::base::unique_fd dm_fd(TEMP_FAILURE_RETRY(open(
+        "/dev/device-mapper", O_RDWR | O_CLOEXEC, 0)));
+    if (dm_fd == -1) {
         PLOG(ERROR) << "Cannot open device-mapper";
         return false;
     }
@@ -165,9 +171,9 @@
         (io->dev & 0xff) | ((io->dev >> 12) & 0xfff00));
 
     io = dm_ioctl_init(buffer, sizeof(buffer), dm_name);
-    unsigned long paramix = io->data_start + sizeof(struct dm_target_spec);
-    unsigned long nullix = paramix + crypt_params.size();
-    unsigned long endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary
+    size_t paramix = io->data_start + sizeof(struct dm_target_spec);
+    size_t nullix = paramix + crypt_params.size();
+    size_t endix = (nullix + 1 + 7) & 8; // Add room for \0 and align to 8 byte boundary
 
     if (endix > sizeof(buffer)) {
         LOG(ERROR) << "crypt_params too big for DM_CRYPT_BUF_SIZE";
@@ -180,7 +186,8 @@
     tgt->sector_start = 0;
     tgt->length = nr_sec;
     target_type.copy(tgt->target_type, sizeof(tgt->target_type));
-    crypt_params.copy(buffer + paramix, sizeof(buffer) - paramix);
+    memcpy(buffer + paramix, crypt_params.data(),
+            std::min(crypt_params.size(), sizeof(buffer) - paramix));
     buffer[nullix] = '\0';
     tgt->next = endix;
 
@@ -244,7 +251,7 @@
 
 bool e4crypt_mount_metadata_encrypted() {
     LOG(DEBUG) << "e4crypt_mount_default_encrypted";
-    std::string key;
+    KeyBuffer key;
     if (!read_key(false, &key)) return false;
     auto data_rec = fs_mgr_get_crypt_entry(fstab);
     if (!data_rec) {
@@ -273,7 +280,7 @@
         return false;
     }
 
-    std::string key_ref;
+    KeyBuffer key_ref;
     if (!read_key(true, &key_ref)) return false;
 
     auto data_rec = fs_mgr_get_crypt_entry(fstab);
diff --git a/MoveTask.cpp b/MoveTask.cpp
index ea64a1c..c565752 100644
--- a/MoveTask.cpp
+++ b/MoveTask.cpp
@@ -62,7 +62,8 @@
             StringPrintf("%d", progress).c_str(), false);
 }
 
-static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd) {
+static status_t pushBackContents(const std::string& path, std::vector<std::string>& cmd,
+        bool addWildcard) {
     DIR* dir = opendir(path.c_str());
     if (dir == NULL) {
         return -1;
@@ -73,7 +74,11 @@
         if ((!strcmp(ent->d_name, ".")) || (!strcmp(ent->d_name, ".."))) {
             continue;
         }
-        cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
+        if (addWildcard) {
+            cmd.push_back(StringPrintf("%s/%s/*", path.c_str(), ent->d_name));
+        } else {
+            cmd.push_back(StringPrintf("%s/%s", path.c_str(), ent->d_name));
+        }
         found = true;
     }
     closedir(dir);
@@ -90,7 +95,7 @@
     cmd.push_back(kRmPath);
     cmd.push_back("-f"); /* force: remove without confirmation, no error if it doesn't exist */
     cmd.push_back("-R"); /* recursive: remove directory contents */
-    if (pushBackContents(path, cmd) != OK) {
+    if (pushBackContents(path, cmd, true) != OK) {
         LOG(WARNING) << "No contents in " << path;
         return OK;
     }
@@ -140,7 +145,7 @@
     cmd.push_back("-R"); /* recurse into subdirectories (DEST must be a directory) */
     cmd.push_back("-P"); /* Do not follow symlinks [default] */
     cmd.push_back("-d"); /* don't dereference symlinks */
-    if (pushBackContents(fromPath, cmd) != OK) {
+    if (pushBackContents(fromPath, cmd, false) != OK) {
         LOG(WARNING) << "No contents in " << fromPath;
         return OK;
     }
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index 119d92c..f976c4a 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -190,6 +190,8 @@
         LOG(VERBOSE) << "Waiting for FUSE to spin up...";
         usleep(50000); // 50ms
     }
+    /* sdcardfs will have exited already. FUSE will still be running */
+    TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, WNOHANG));
 
     return OK;
 }
diff --git a/Utils.cpp b/Utils.cpp
index c9d7d05..b6c7bf8 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -351,18 +351,20 @@
 }
 
 status_t ReadRandomBytes(size_t bytes, std::string& out) {
-    out.clear();
+    out.resize(bytes);
+    return ReadRandomBytes(bytes, &out[0]);
+}
 
+status_t ReadRandomBytes(size_t bytes, char* buf) {
     int fd = TEMP_FAILURE_RETRY(open("/dev/urandom", O_RDONLY | O_CLOEXEC | O_NOFOLLOW));
     if (fd == -1) {
         return -errno;
     }
 
-    char buf[BUFSIZ];
     size_t n;
-    while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], std::min(sizeof(buf), bytes)))) > 0) {
-        out.append(buf, n);
+    while ((n = TEMP_FAILURE_RETRY(read(fd, &buf[0], bytes))) > 0) {
         bytes -= n;
+        buf += n;
     }
     close(fd);
 
@@ -373,6 +375,17 @@
     }
 }
 
+status_t GenerateRandomUuid(std::string& out) {
+    status_t res = ReadRandomBytes(16, out);
+    if (res == OK) {
+        out[6] &= 0x0f;  /* clear version        */
+        out[6] |= 0x40;  /* set to version 4     */
+        out[8] &= 0x3f;  /* clear variant        */
+        out[8] |= 0x80;  /* set to IETF variant  */
+    }
+    return res;
+}
+
 status_t HexToStr(const std::string& hex, std::string& str) {
     str.clear();
     bool even = true;
@@ -423,6 +436,15 @@
     return OK;
 }
 
+status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex) {
+    hex.clear();
+    for (size_t i = 0; i < str.size(); i++) {
+        hex.push_back(kLookup[(str.data()[i] & 0xF0) >> 4]);
+        hex.push_back(kLookup[str.data()[i] & 0x0F]);
+    }
+    return OK;
+}
+
 status_t NormalizeHex(const std::string& in, std::string& out) {
     std::string tmp;
     if (HexToStr(in, tmp)) {
diff --git a/Utils.h b/Utils.h
index 813ffac..82ac440 100644
--- a/Utils.h
+++ b/Utils.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_VOLD_UTILS_H
 #define ANDROID_VOLD_UTILS_H
 
+#include "KeyBuffer.h"
+
 #include <utils/Errors.h>
 #include <cutils/multiuser.h>
 #include <selinux/selinux.h>
@@ -78,11 +80,15 @@
 pid_t ForkExecvpAsync(const std::vector<std::string>& args);
 
 status_t ReadRandomBytes(size_t bytes, std::string& out);
+status_t ReadRandomBytes(size_t bytes, char* buffer);
+status_t GenerateRandomUuid(std::string& out);
 
 /* Converts hex string to raw bytes, ignoring [ :-] */
 status_t HexToStr(const std::string& hex, std::string& str);
 /* Converts raw bytes to hex string */
 status_t StrToHex(const std::string& str, std::string& hex);
+/* Converts raw key bytes to hex string */
+status_t StrToHex(const KeyBuffer& str, KeyBuffer& hex);
 /* Normalize given hex string into consistent format */
 status_t NormalizeHex(const std::string& in, std::string& out);
 
diff --git a/cryptfs.cpp b/cryptfs.cpp
index 5b863ba..d153a99 100644
--- a/cryptfs.cpp
+++ b/cryptfs.cpp
@@ -1301,29 +1301,24 @@
     return rc;
 }
 
-static int prep_data_fs(void)
+static void prep_data_fs(void)
 {
-    int i;
-
     // NOTE: post_fs_data results in init calling back around to vold, so all
     // callers to this method must be async
 
     /* Do the prep of the /data filesystem */
     property_set("vold.post_fs_data_done", "0");
     property_set("vold.decrypt", "trigger_post_fs_data");
-    SLOGD("Just triggered post_fs_data\n");
+    SLOGD("Just triggered post_fs_data");
 
     /* Wait a max of 50 seconds, hopefully it takes much less */
-    if (!android::base::WaitForProperty("vold.post_fs_data_done",
+    while (!android::base::WaitForProperty("vold.post_fs_data_done",
                                         "1",
-                                        std::chrono::seconds(50))) {
-        /* Ugh, we failed to prep /data in time.  Bail. */
-        SLOGE("post_fs_data timed out!\n");
-        return -1;
-    } else {
-        SLOGD("post_fs_data done\n");
-        return 0;
+                                        std::chrono::seconds(15))) {
+        /* We timed out to prep /data in time.  Continue wait. */
+        SLOGE("waited 15s for vold.post_fs_data_done, still waiting...");
     }
+    SLOGD("post_fs_data done");
 }
 
 static void cryptfs_set_corrupt()
@@ -1474,9 +1469,7 @@
         }
 
         /* Create necessary paths on /data */
-        if (prep_data_fs()) {
-            return -1;
-        }
+        prep_data_fs();
         property_set("vold.decrypt", "trigger_load_persist_props");
 
         /* startup service classes main and late_start */
@@ -2215,9 +2208,7 @@
 
         /* restart the framework. */
         /* Create necessary paths on /data */
-        if (prep_data_fs()) {
-            goto error_shutting_down;
-        }
+        prep_data_fs();
 
         /* Ugh, shutting down the framework is not synchronous, so until it
          * can be fixed, this horrible hack will wait a moment for it all to
diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp
index 0670bb5..0cf4f9e 100644
--- a/fs/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -38,6 +38,7 @@
 #define LOG_TAG "Vold"
 
 #include <android-base/logging.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
@@ -45,6 +46,7 @@
 #include <selinux/selinux.h>
 
 #include "Ext4.h"
+#include "Ext4Crypt.h"
 #include "Utils.h"
 #include "VoldUtil.h"
 
@@ -55,11 +57,7 @@
 namespace ext4 {
 
 static const char* kResizefsPath = "/system/bin/resize2fs";
-#ifdef TARGET_USES_MKE2FS
 static const char* kMkfsPath = "/system/bin/mke2fs";
-#else
-static const char* kMkfsPath = "/system/bin/make_ext4fs";
-#endif
 static const char* kFsckPath = "/system/bin/e2fsck";
 
 bool IsSupported() {
@@ -170,7 +168,6 @@
     std::vector<std::string> cmd;
     cmd.push_back(kMkfsPath);
 
-#ifdef TARGET_USES_MKE2FS
     cmd.push_back("-b");
     cmd.push_back("4096");
 
@@ -180,28 +177,22 @@
     cmd.push_back("-M");
     cmd.push_back(target);
 
-    cmd.push_back("-O");
-    cmd.push_back("^has_journal");
-
-    cmd.push_back(source);
-
-    if (numSectors)
-        cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
-#else
-    cmd.push_back("-J");
-
-    cmd.push_back("-a");
-    cmd.push_back(target);
-
-    if (numSectors) {
-        cmd.push_back("-l");
-        cmd.push_back(StringPrintf("%lu", numSectors * 512));
+    std::string options("has_journal");
+    if (android::base::GetBoolProperty("vold.has_quota", false)) {
+        options += ",quota";
+    }
+    if (e4crypt_is_native()) {
+        options += ",encrypt";
     }
 
-    // Always generate a real UUID
-    cmd.push_back("-u");
+    cmd.push_back("-O");
+    cmd.push_back(options);
+
     cmd.push_back(source);
-#endif
+
+    if (numSectors) {
+        cmd.push_back(StringPrintf("%lu", numSectors * (4096 / 512)));
+    }
 
     return ForkExecvp(cmd);
 }
diff --git a/fs/Vfat.cpp b/fs/Vfat.cpp
index 1803c4b..dc1fe33 100644
--- a/fs/Vfat.cpp
+++ b/fs/Vfat.cpp
@@ -133,7 +133,7 @@
     const char* c_source = source.c_str();
     const char* c_target = target.c_str();
 
-    flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+    flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME;
 
     flags |= (executable ? 0 : MS_NOEXEC);
     flags |= (ro ? MS_RDONLY : 0);
diff --git a/main.cpp b/main.cpp
index 4657377..30c839e 100644
--- a/main.cpp
+++ b/main.cpp
@@ -39,7 +39,7 @@
 #include <dirent.h>
 #include <fs_mgr.h>
 
-static int process_config(VolumeManager *vm, bool* has_adoptable);
+static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota);
 static void coldboot(const char *path);
 static void parse_args(int argc, char** argv);
 
@@ -107,8 +107,9 @@
     }
 
     bool has_adoptable;
+    bool has_quota;
 
-    if (process_config(vm, &has_adoptable)) {
+    if (process_config(vm, &has_adoptable, &has_quota)) {
         PLOG(ERROR) << "Error reading configuration... continuing anyways";
     }
 
@@ -133,6 +134,7 @@
     // This call should go after listeners are started to avoid
     // a deadlock between vold and init (see b/34278978 for details)
     property_set("vold.has_adoptable", has_adoptable ? "1" : "0");
+    property_set("vold.has_quota", has_quota ? "1" : "0");
 
     // Do coldboot here so it won't block booting,
     // also the cold boot is needed in case we have flash drive
@@ -214,7 +216,7 @@
     }
 }
 
-static int process_config(VolumeManager *vm, bool* has_adoptable) {
+static int process_config(VolumeManager *vm, bool* has_adoptable, bool* has_quota) {
     fstab = fs_mgr_read_fstab_default();
     if (!fstab) {
         PLOG(ERROR) << "Failed to open default fstab";
@@ -223,7 +225,12 @@
 
     /* Loop through entries looking for ones that vold manages */
     *has_adoptable = false;
+    *has_quota = false;
     for (int i = 0; i < fstab->num_entries; i++) {
+        if (fs_mgr_is_quota(&fstab->recs[i])) {
+            *has_quota = true;
+        }
+
         if (fs_mgr_is_voldmanaged(&fstab->recs[i])) {
             if (fs_mgr_is_nonremovable(&fstab->recs[i])) {
                 LOG(WARNING) << "nonremovable no longer supported; ignoring volume";
diff --git a/secdiscard.cpp b/secdiscard.cpp
index fe51990..f9532ea 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -29,8 +29,9 @@
 #include <mntent.h>
 
 #include <android-base/logging.h>
+#include <android-base/unique_fd.h>
 
-#include <AutoCloseFD.h>
+#include "FileDeviceUtils.h"
 
 namespace {
 
@@ -44,10 +45,7 @@
 bool read_command_line(int argc, const char * const argv[], Options &options);
 void usage(const char *progname);
 bool secdiscard_path(const std::string &path);
-std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count);
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path);
-std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count);
-std::string block_device_for_path(const std::string &path);
 bool overwrite_with_zeros(int fd, off64_t start, off64_t length);
 
 }
@@ -99,16 +97,17 @@
 
 // BLKSECDISCARD all content in "path", if it's small enough.
 bool secdiscard_path(const std::string &path) {
-    auto fiemap = path_fiemap(path, max_extents);
+    auto fiemap = android::vold::PathFiemap(path, max_extents);
     if (!fiemap || !check_fiemap(*fiemap, path)) {
         return false;
     }
-    auto block_device = block_device_for_path(path);
+    auto block_device = android::vold::BlockDeviceForPath(path);
     if (block_device.empty()) {
         return false;
     }
-    AutoCloseFD fs_fd(block_device, O_RDWR | O_LARGEFILE);
-    if (!fs_fd) {
+    android::base::unique_fd fs_fd(TEMP_FAILURE_RETRY(open(
+        block_device.c_str(), O_RDWR | O_LARGEFILE | O_CLOEXEC, 0)));
+    if (fs_fd == -1) {
         PLOG(ERROR) << "Failed to open device " << block_device;
         return false;
     }
@@ -125,32 +124,6 @@
     return true;
 }
 
-// Read the file's FIEMAP
-std::unique_ptr<struct fiemap> path_fiemap(const std::string &path, uint32_t extent_count)
-{
-    AutoCloseFD fd(path);
-    if (!fd) {
-        if (errno == ENOENT) {
-            PLOG(DEBUG) << "Unable to open " << path;
-        } else {
-            PLOG(ERROR) << "Unable to open " << path;
-        }
-        return nullptr;
-    }
-    auto fiemap = alloc_fiemap(extent_count);
-    if (ioctl(fd.get(), FS_IOC_FIEMAP, fiemap.get()) != 0) {
-        PLOG(ERROR) << "Unable to FIEMAP " << path;
-        return nullptr;
-    }
-    auto mapped = fiemap->fm_mapped_extents;
-    if (mapped < 1 || mapped > extent_count) {
-        LOG(ERROR) << "Extent count not in bounds 1 <= " << mapped << " <= " << extent_count
-            << " in " << path;
-        return nullptr;
-    }
-    return fiemap;
-}
-
 // Ensure that the FIEMAP covers the file and is OK to discard
 bool check_fiemap(const struct fiemap &fiemap, const std::string &path) {
     auto mapped = fiemap.fm_mapped_extents;
@@ -168,48 +141,6 @@
     return true;
 }
 
-std::unique_ptr<struct fiemap> alloc_fiemap(uint32_t extent_count)
-{
-    size_t allocsize = offsetof(struct fiemap, fm_extents[extent_count]);
-    std::unique_ptr<struct fiemap> res(new (::operator new (allocsize)) struct fiemap);
-    memset(res.get(), 0, allocsize);
-    res->fm_start = 0;
-    res->fm_length = UINT64_MAX;
-    res->fm_flags = 0;
-    res->fm_extent_count = extent_count;
-    res->fm_mapped_extents = 0;
-    return res;
-}
-
-// Given a file path, look for the corresponding block device in /proc/mount
-std::string block_device_for_path(const std::string &path)
-{
-    std::unique_ptr<FILE, int(*)(FILE*)> mnts(setmntent("/proc/mounts", "re"), endmntent);
-    if (!mnts) {
-        PLOG(ERROR) << "Unable to open /proc/mounts";
-        return "";
-    }
-    std::string result;
-    size_t best_length = 0;
-    struct mntent *mnt; // getmntent returns a thread local, so it's safe.
-    while ((mnt = getmntent(mnts.get())) != nullptr) {
-        auto l = strlen(mnt->mnt_dir);
-        if (l > best_length &&
-            path.size() > l &&
-            path[l] == '/' &&
-            path.compare(0, l, mnt->mnt_dir) == 0) {
-                result = mnt->mnt_fsname;
-                best_length = l;
-        }
-    }
-    if (result.empty()) {
-        LOG(ERROR) <<"Didn't find a mountpoint to match path " << path;
-        return "";
-    }
-    LOG(DEBUG) << "For path " << path << " block device is " << result;
-    return result;
-}
-
 bool overwrite_with_zeros(int fd, off64_t start, off64_t length) {
     if (lseek64(fd, start, SEEK_SET) != start) {
         PLOG(ERROR) << "Seek failed for zero overwrite";