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