recovery: Implement a volume manager

This is a copy of the pre-binderized vold which has been converted to
use direct calls instead of sockets and stripped down to only what is
needed to support recovery.

Change-Id: Ic82d929e052b5ba70ecf7b475e0a223d77d9687e
diff --git a/volume_manager/fs/Exfat.cpp b/volume_manager/fs/Exfat.cpp
new file mode 100644
index 0000000..f858e13
--- /dev/null
+++ b/volume_manager/fs/Exfat.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 "Exfat.h"
+#include "Utils.h"
+
+#define LOG_TAG "Vold"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <cutils/log.h>
+
+#include <logwrap/logwrap.h>
+
+#include <string>
+#include <vector>
+
+#include <sys/mount.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace volmgr {
+namespace exfat {
+
+static const char* kFsckPath = "/sbin/fsck.exfat";
+
+bool IsSupported() {
+    return access(kFsckPath, X_OK) == 0 && IsFilesystemSupported("exfat");
+}
+
+status_t Check(const std::string& source) {
+    std::vector<std::string> cmd;
+    cmd.push_back(kFsckPath);
+    cmd.push_back(source);
+
+    // Exfat devices are currently always untrusted
+    return ForkExecvp(cmd, sFsckUntrustedContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target, int ownerUid, int ownerGid,
+               int permMask) {
+    int mountFlags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME | MS_NOEXEC;
+    auto mountData = android::base::StringPrintf("uid=%d,gid=%d,fmask=%o,dmask=%o", ownerUid,
+                                                 ownerGid, permMask, permMask);
+
+    if (mount(source.c_str(), target.c_str(), "exfat", mountFlags, mountData.c_str()) == 0) {
+        return 0;
+    }
+    PLOG(ERROR) << "Mount failed; attempting read-only";
+    mountFlags |= MS_RDONLY;
+    if (mount(source.c_str(), target.c_str(), "exfat", mountFlags, mountData.c_str()) == 0) {
+        return 0;
+    }
+
+    return -1;
+}
+
+}  // namespace exfat
+}  // namespace volmgr
+}  // namespace android
diff --git a/volume_manager/fs/Exfat.h b/volume_manager/fs/Exfat.h
new file mode 100644
index 0000000..f694fdf
--- /dev/null
+++ b/volume_manager/fs/Exfat.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 VOLMGR_EXFAT_H
+#define VOLMGR_EXFAT_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace volmgr {
+namespace exfat {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target, int ownerUid, int ownerGid,
+               int permMask);
+
+}  // namespace exfat
+}  // namespace volmgr
+}  // namespace android
+
+#endif
diff --git a/volume_manager/fs/Ext4.cpp b/volume_manager/fs/Ext4.cpp
new file mode 100644
index 0000000..1b02fed
--- /dev/null
+++ b/volume_manager/fs/Ext4.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <string>
+#include <vector>
+
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <linux/kdev_t.h>
+
+#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>
+#include <logwrap/logwrap.h>
+#include <private/android_filesystem_config.h>
+#include <selinux/selinux.h>
+
+#include "Ext4.h"
+#include "Utils.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace volmgr {
+namespace ext4 {
+
+static const char* kFsckPath = "/sbin/e2fsck";
+
+bool IsSupported() {
+    return access(kFsckPath, X_OK) == 0 && IsFilesystemSupported("ext4");
+}
+
+status_t Check(const std::string& source, const std::string& target, bool trusted) {
+    // The following is shamelessly borrowed from fs_mgr.c, so it should be
+    // kept in sync with any changes over there.
+
+    const char* c_source = source.c_str();
+    const char* c_target = target.c_str();
+
+    int ret;
+    long tmpmnt_flags = MS_NOATIME | MS_NOEXEC | MS_NOSUID;
+    char* tmpmnt_opts = (char*)"nomblk_io_submit,errors=remount-ro";
+
+    /*
+     * First try to mount and unmount the filesystem.  We do this because
+     * the kernel is more efficient than e2fsck in running the journal and
+     * processing orphaned inodes, and on at least one device with a
+     * performance issue in the emmc firmware, it can take e2fsck 2.5 minutes
+     * to do what the kernel does in about a second.
+     *
+     * After mounting and unmounting the filesystem, run e2fsck, and if an
+     * error is recorded in the filesystem superblock, e2fsck will do a full
+     * check.  Otherwise, it does nothing.  If the kernel cannot mount the
+     * filesytsem due to an error, e2fsck is still run to do a full check
+     * fix the filesystem.
+     */
+    ret = mount(c_source, c_target, "ext4", tmpmnt_flags, tmpmnt_opts);
+    if (!ret) {
+        int i;
+        for (i = 0; i < 5; i++) {
+            // Try to umount 5 times before continuing on.
+            // Should we try rebooting if all attempts fail?
+            int result = umount(c_target);
+            if (result == 0) {
+                break;
+            }
+            ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno));
+            sleep(1);
+        }
+    }
+
+    /*
+     * Some system images do not have e2fsck for licensing reasons
+     * (e.g. recent SDK system images). Detect these and skip the check.
+     */
+    if (access(kFsckPath, X_OK)) {
+        ALOGD("Not running %s on %s (executable not in system image)\n", kFsckPath, c_source);
+    } else {
+        ALOGD("Running %s on %s\n", kFsckPath, c_source);
+
+        std::vector<std::string> cmd;
+        cmd.push_back(kFsckPath);
+        cmd.push_back("-y");
+        cmd.push_back(c_source);
+
+        return ForkExecvp(cmd, trusted ? sFsckContext : sFsckUntrustedContext);
+    }
+
+    return 0;
+}
+
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, const std::string& opts /* = "" */, bool trusted, bool portable) {
+    int rc;
+    unsigned long flags;
+
+    std::string data(opts);
+
+    if (portable) {
+        if (!data.empty()) {
+            data += ",";
+        }
+        data += "context=u:object_r:sdcard_posix:s0";
+    }
+    const char* c_source = source.c_str();
+    const char* c_target = target.c_str();
+    const char* c_data = data.c_str();
+
+    flags = MS_NOATIME | MS_NODEV | MS_NOSUID;
+
+    // Only use MS_DIRSYNC if we're not mounting adopted storage
+    if (!trusted) {
+        flags |= MS_DIRSYNC;
+    }
+
+    flags |= (executable ? 0 : MS_NOEXEC);
+    flags |= (ro ? MS_RDONLY : 0);
+    flags |= (remount ? MS_REMOUNT : 0);
+
+    rc = mount(c_source, c_target, "ext4", flags, c_data);
+    if (portable && rc == 0) {
+        chown(c_target, AID_MEDIA_RW, AID_MEDIA_RW);
+        chmod(c_target, 0775);
+    }
+
+    if (rc && errno == EROFS) {
+        SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
+        flags |= MS_RDONLY;
+        rc = mount(c_source, c_target, "ext4", flags, c_data);
+    }
+
+    return rc;
+}
+
+}  // namespace ext4
+}  // namespace volmgr
+}  // namespace android
diff --git a/volume_manager/fs/Ext4.h b/volume_manager/fs/Ext4.h
new file mode 100644
index 0000000..d049b45
--- /dev/null
+++ b/volume_manager/fs/Ext4.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 VOLMGR_EXT4_H
+#define VOLMGR_EXT4_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace volmgr {
+namespace ext4 {
+
+bool IsSupported();
+
+status_t Check(const std::string& source, const std::string& target, bool trusted);
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, const std::string& opts = "", bool trusted = false,
+               bool portable = false);
+
+}  // namespace ext4
+}  // namespace volmgr
+}  // namespace android
+
+#endif
diff --git a/volume_manager/fs/F2fs.cpp b/volume_manager/fs/F2fs.cpp
new file mode 100644
index 0000000..ae0e1ba
--- /dev/null
+++ b/volume_manager/fs/F2fs.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 "F2fs.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <private/android_filesystem_config.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <string>
+#include <vector>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace volmgr {
+namespace f2fs {
+
+static const char* kFsckPath = "/sbin/fsck.f2fs";
+
+bool IsSupported() {
+    return access(kFsckPath, X_OK) == 0 && IsFilesystemSupported("f2fs");
+}
+
+status_t Check(const std::string& source, bool trusted) {
+    std::vector<std::string> cmd;
+    cmd.push_back(kFsckPath);
+    cmd.push_back("-a");
+    cmd.push_back(source);
+
+    return ForkExecvp(cmd, trusted ? sFsckContext : sFsckUntrustedContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target,
+               const std::string& opts /* = "" */, bool trusted, bool portable) {
+    std::string data(opts);
+
+    if (portable) {
+        if (!data.empty()) {
+            data += ",";
+        }
+        data += "context=u:object_r:sdcard_posix:s0";
+    }
+
+    const char* c_source = source.c_str();
+    const char* c_target = target.c_str();
+    const char* c_data = data.c_str();
+
+    unsigned long flags = MS_NOATIME | MS_NODEV | MS_NOSUID;
+
+    // Only use MS_DIRSYNC if we're not mounting adopted storage
+    if (!trusted) {
+        flags |= MS_DIRSYNC;
+    }
+
+    int res = mount(c_source, c_target, "f2fs", flags, c_data);
+    if (portable && res == 0) {
+        chown(c_target, AID_MEDIA_RW, AID_MEDIA_RW);
+        chmod(c_target, 0775);
+    }
+
+    if (res != 0) {
+        PLOG(ERROR) << "Failed to mount " << source;
+        if (errno == EROFS) {
+            res = mount(c_source, c_target, "f2fs", flags | MS_RDONLY, c_data);
+            if (res != 0) {
+                PLOG(ERROR) << "Failed to mount read-only " << source;
+            }
+        }
+    }
+
+    return res;
+}
+
+}  // namespace f2fs
+}  // namespace volmgr
+}  // namespace android
diff --git a/volume_manager/fs/F2fs.h b/volume_manager/fs/F2fs.h
new file mode 100644
index 0000000..b3633e5
--- /dev/null
+++ b/volume_manager/fs/F2fs.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 VOLMGR_F2FS_H
+#define VOLMGR_F2FS_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace volmgr {
+namespace f2fs {
+
+bool IsSupported();
+
+status_t Check(const std::string& source, bool trusted);
+status_t Mount(const std::string& source, const std::string& target, const std::string& opts = "",
+               bool trusted = false, bool portable = false);
+
+}  // namespace f2fs
+}  // namespace volmgr
+}  // namespace android
+
+#endif
diff --git a/volume_manager/fs/Ntfs.cpp b/volume_manager/fs/Ntfs.cpp
new file mode 100644
index 0000000..798e58d
--- /dev/null
+++ b/volume_manager/fs/Ntfs.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 "Ntfs.h"
+#include "Utils.h"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+
+#include <string>
+#include <vector>
+
+#include <sys/mount.h>
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace volmgr {
+namespace ntfs {
+
+static const char* kFsckPath = "/sbin/fsck.ntfs";
+static const char* kMountPath = "/sbin/mount.ntfs";
+
+bool IsSupported() {
+    return access(kFsckPath, X_OK) == 0 && access(kMountPath, X_OK) == 0 &&
+           IsFilesystemSupported("ntfs");
+}
+
+status_t Check(const std::string& source) {
+    std::vector<std::string> cmd;
+    cmd.push_back(kFsckPath);
+    cmd.push_back("-n");
+    cmd.push_back(source);
+
+    // Ntfs devices are currently always untrusted
+    return ForkExecvp(cmd, sFsckUntrustedContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, int ownerUid, int ownerGid, int permMask) {
+    char mountData[255];
+
+    const char* c_source = source.c_str();
+    const char* c_target = target.c_str();
+
+    sprintf(mountData,
+            "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,"
+            "shortname=mixed,nodev,nosuid,dirsync",
+            ownerUid, ownerGid, permMask, permMask);
+
+    if (!executable) strlcat(mountData, ",noexec", sizeof(mountData));
+    if (ro) strlcat(mountData, ",ro", sizeof(mountData));
+    if (remount) strlcat(mountData, ",remount", sizeof(mountData));
+
+    std::vector<std::string> cmd;
+    cmd.push_back(kMountPath);
+    cmd.push_back("-o");
+    cmd.push_back(mountData);
+    cmd.push_back(c_source);
+    cmd.push_back(c_target);
+
+    return ForkExecvp(cmd);
+}
+
+}  // namespace ntfs
+}  // namespace volmgr
+}  // namespace android
diff --git a/volume_manager/fs/Ntfs.h b/volume_manager/fs/Ntfs.h
new file mode 100644
index 0000000..03c0627
--- /dev/null
+++ b/volume_manager/fs/Ntfs.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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_NTFS_H
+#define ANDROID_VOLD_NTFS_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace volmgr {
+namespace ntfs {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, int ownerUid, int ownerGid, int permMask);
+
+}  // namespace ntfs
+}  // namespace volmgr
+}  // namespace android
+
+#endif
diff --git a/volume_manager/fs/Vfat.cpp b/volume_manager/fs/Vfat.cpp
new file mode 100644
index 0000000..bbbcd6e
--- /dev/null
+++ b/volume_manager/fs/Vfat.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <linux/fs.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <linux/kdev_t.h>
+
+#define LOG_TAG "Vold"
+
+#include <android-base/logging.h>
+#include <android-base/stringprintf.h>
+#include <cutils/log.h>
+#include <cutils/properties.h>
+#include <selinux/selinux.h>
+
+#include <logwrap/logwrap.h>
+
+#include "Utils.h"
+#include "Vfat.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace volmgr {
+namespace vfat {
+
+static const char* kFsckPath = "/sbin/fsck_msdos";
+
+bool IsSupported() {
+    return access(kFsckPath, X_OK) == 0 && IsFilesystemSupported("vfat");
+}
+
+status_t Check(const std::string& source) {
+    if (access(kFsckPath, X_OK)) {
+        SLOGW("Skipping fs checks\n");
+        return 0;
+    }
+
+    int pass = 1;
+    int rc = 0;
+    do {
+        std::vector<std::string> cmd;
+        cmd.push_back(kFsckPath);
+        cmd.push_back("-p");
+        cmd.push_back("-f");
+        cmd.push_back(source);
+
+        // Fat devices are currently always untrusted
+        rc = ForkExecvp(cmd, sFsckUntrustedContext);
+
+        if (rc < 0) {
+            SLOGE("Filesystem check failed due to logwrap error");
+            errno = EIO;
+            return -1;
+        }
+
+        switch (rc) {
+            case 0:
+                SLOGI("Filesystem check completed OK");
+                return 0;
+
+            case 2:
+                SLOGE("Filesystem check failed (not a FAT filesystem)");
+                errno = ENODATA;
+                return -1;
+
+            case 4:
+                if (pass++ <= 3) {
+                    SLOGW("Filesystem modified - rechecking (pass %d)", pass);
+                    continue;
+                }
+                SLOGE("Failing check after too many rechecks");
+                errno = EIO;
+                return -1;
+
+            case 8:
+                SLOGE("Filesystem check failed (no filesystem)");
+                errno = ENODATA;
+                return -1;
+
+            default:
+                SLOGE("Filesystem check failed (unknown exit code %d)", rc);
+                errno = EIO;
+                return -1;
+        }
+    } while (0);
+
+    return 0;
+}
+
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, int ownerUid, int ownerGid, int permMask, bool createLost) {
+    int rc;
+    unsigned long flags;
+    char mountData[255];
+
+    const char* c_source = source.c_str();
+    const char* c_target = target.c_str();
+
+    flags = MS_NODEV | MS_NOSUID | MS_DIRSYNC | MS_NOATIME;
+
+    flags |= (executable ? 0 : MS_NOEXEC);
+    flags |= (ro ? MS_RDONLY : 0);
+    flags |= (remount ? MS_REMOUNT : 0);
+
+    snprintf(mountData, sizeof(mountData), "utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
+             ownerUid, ownerGid, permMask, permMask);
+
+    rc = mount(c_source, c_target, "vfat", flags, mountData);
+
+    if (rc && errno == EROFS) {
+        SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
+        flags |= MS_RDONLY;
+        rc = mount(c_source, c_target, "vfat", flags, mountData);
+    }
+
+    if (rc == 0 && createLost) {
+        char* lost_path;
+        asprintf(&lost_path, "%s/LOST.DIR", c_target);
+        if (access(lost_path, F_OK)) {
+            /*
+             * Create a LOST.DIR in the root so we have somewhere to put
+             * lost cluster chains (fsck_msdos doesn't currently do this)
+             */
+            if (mkdir(lost_path, 0755)) {
+                SLOGE("Unable to create LOST.DIR (%s)", strerror(errno));
+            }
+        }
+        free(lost_path);
+    }
+
+    return rc;
+}
+
+}  // namespace vfat
+}  // namespace volmgr
+}  // namespace android
diff --git a/volume_manager/fs/Vfat.h b/volume_manager/fs/Vfat.h
new file mode 100644
index 0000000..6e4a58b
--- /dev/null
+++ b/volume_manager/fs/Vfat.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2019 The LineageOS 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 VOLMGR_VFAT_H
+#define VOLMGR_VFAT_H
+
+#include <utils/Errors.h>
+
+#include <string>
+
+namespace android {
+namespace volmgr {
+namespace vfat {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target, bool ro, bool remount,
+               bool executable, int ownerUid, int ownerGid, int permMask, bool createLost);
+
+}  // namespace vfat
+}  // namespace volmgr
+}  // namespace android
+
+#endif