From 584c493f5e5ae3ae537898baf2bce47a5b7ea4c8 Mon Sep 17 00:00:00 2001 From: Dan Pasanen Date: Tue, 27 Oct 2015 22:52:37 -0500 Subject: [PATCH] vold: add support for more filesystems for public storage * Add exfat and ntfs support based off f2fs and ported to use fuse * Add support for both along with f2fs and ext4 to PublicVolume * Also attempt to mount any volume if it's been determined that the kernel supports it Change-Id: I0a83761cefd97791e3ec84a18e199dfd27a5ed0b vold: fs: Fix build errors * Migrate from base to android-base * Add missing , in Ext4 Mount function [AdrianDC] Ignore unpatched ext4 arguments [mikeioannina] Update for Pie native exfat Change-Id: I875b5763c472aa7da2976ec7c5db7cf28c913876 vold: ntfs: Use strlcat Clang now enforces length checking :/ Change-Id: I495b4cb2ee530e72b1084248f0549d63589523b0 Change-Id: I0a83761cefd97791e3ec84a18e199dfd27a5ed0b --- Android.bp | 1 + Utils.cpp | 4 ++ fs/Ntfs.cpp | 104 +++++++++++++++++++++++++++++++++++++++++ fs/Ntfs.h | 39 ++++++++++++++++ main.cpp | 2 + model/Disk.cpp | 1 + model/PublicVolume.cpp | 77 ++++++++++++++++++++---------- 7 files changed, 204 insertions(+), 24 deletions(-) create mode 100644 fs/Ntfs.cpp create mode 100644 fs/Ntfs.h diff --git a/Android.bp b/Android.bp index 1f8d274..711b7a5 100644 --- a/Android.bp +++ b/Android.bp @@ -140,6 +140,7 @@ cc_library_static { "fs/Exfat.cpp", "fs/Ext4.cpp", "fs/F2fs.cpp", + "fs/Ntfs.cpp", "fs/Vfat.cpp", "model/Disk.cpp", "model/EmulatedVolume.cpp", diff --git a/Utils.cpp b/Utils.cpp index 17921e8..8ce1370 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1000,6 +1000,10 @@ bool IsFilesystemSupported(const std::string& fsType) { PLOG(ERROR) << "Failed to read supported filesystems"; return false; } + + /* fuse filesystems */ + supported.append("fuse\tntfs\n"); + return supported.find(fsType + "\n") != std::string::npos; } diff --git a/fs/Ntfs.cpp b/fs/Ntfs.cpp new file mode 100644 index 0000000..6be65bc --- /dev/null +++ b/fs/Ntfs.cpp @@ -0,0 +1,104 @@ +/* + * 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 + +#include +#include + +#include + +#include "Ntfs.h" +#include "Utils.h" + +using android::base::StringPrintf; + +namespace android { +namespace vold { +namespace ntfs { + +static const char* kMkfsPath = "/system/bin/mkfs.ntfs"; +static const char* kFsckPath = "/system/bin/fsck.ntfs"; +static const char* kMountPath = "/system/bin/mount.ntfs"; + +bool IsSupported() { + return access(kMkfsPath, X_OK) == 0 + && access(kFsckPath, X_OK) == 0 + && access(kMountPath, X_OK) == 0 + && IsFilesystemSupported("ntfs"); +} + +status_t Check(const std::string& source) { + std::vector cmd; + cmd.push_back(kFsckPath); + cmd.push_back("-n"); + cmd.push_back(source); + + int rc = ForkExecvp(cmd, nullptr, sFsckUntrustedContext); + if (rc == 0) { + LOG(INFO) << "Check OK"; + return 0; + } else { + LOG(ERROR) << "Check failed (code " << rc << ")"; + errno = EIO; + return -1; + } +} + +status_t Mount(const std::string& source, const std::string& target, int ownerUid, int ownerGid, + int permMask) { + auto mountData = android::base::StringPrintf("utf8,uid=%d,gid=%d,fmask=%o,dmask=%o," + "shortname=mixed,nodev,nosuid,dirsync,noatime," + "noexec", ownerUid, ownerGid, permMask, permMask); + + std::vector cmd; + cmd.push_back(kMountPath); + cmd.push_back("-o"); + cmd.push_back(mountData.c_str()); + cmd.push_back(source.c_str()); + cmd.push_back(target.c_str()); + + int rc = ForkExecvp(cmd); + if (rc == 0) { + LOG(INFO) << "Mount OK"; + return 0; + } else { + LOG(ERROR) << "Mount failed (code " << rc << ")"; + errno = EIO; + return -1; + } +} + +status_t Format(const std::string& source) { + std::vector cmd; + cmd.push_back(kMkfsPath); + cmd.push_back(source); + + int rc = ForkExecvp(cmd); + if (rc == 0) { + LOG(INFO) << "Format OK"; + return 0; + } else { + LOG(ERROR) << "Format failed (code " << rc << ")"; + errno = EIO; + return -1; + } + return 0; +} + +} // namespace ntfs +} // namespace vold +} // namespace android diff --git a/fs/Ntfs.h b/fs/Ntfs.h new file mode 100644 index 0000000..2f002b2 --- /dev/null +++ b/fs/Ntfs.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef ANDROID_VOLD_NTFS_H +#define ANDROID_VOLD_NTFS_H + +#include + +#include + +namespace android { +namespace vold { +namespace ntfs { + +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); +status_t Format(const std::string& source); + +} // namespace ntfs +} // namespace vold +} // namespace android + +#endif diff --git a/main.cpp b/main.cpp index ebe5510..a6cb640 100644 --- a/main.cpp +++ b/main.cpp @@ -61,8 +61,10 @@ int main(int argc, char** argv) { ATRACE_BEGIN("main"); LOG(DEBUG) << "Detected support for:" + << (android::vold::IsFilesystemSupported("exfat") ? " exfat" : "") << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "") << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "") + << (android::vold::IsFilesystemSupported("ntfs") ? " ntfs" : "") << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : ""); VolumeManager* vm; diff --git a/model/Disk.cpp b/model/Disk.cpp index 3da0f14..f0fa02e 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -401,6 +401,7 @@ status_t Disk::readPartitions() { case 0x0b: // W95 FAT32 (LBA) case 0x0c: // W95 FAT32 (LBA) case 0x0e: // W95 FAT16 (LBA) + case 0x83: // Linux EXT4/F2FS/... createPublicVolume(partDevice); break; } diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index d40e3e3..0719e51 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -20,6 +20,9 @@ #include "Utils.h" #include "VolumeManager.h" #include "fs/Exfat.h" +#include "fs/Ext4.h" +#include "fs/F2fs.h" +#include "fs/Ntfs.h" #include "fs/Vfat.h" #include @@ -100,17 +103,7 @@ status_t PublicVolume::doMount() { bool isVisible = getMountFlags() & MountFlags::kVisible; readMetadata(); - if (mFsType == "vfat" && vfat::IsSupported()) { - if (vfat::Check(mDevPath)) { - LOG(ERROR) << getId() << " failed filesystem check"; - return -EIO; - } - } else if (mFsType == "exfat" && exfat::IsSupported()) { - if (exfat::Check(mDevPath)) { - LOG(ERROR) << getId() << " failed filesystem check"; - return -EIO; - } - } else { + if (!IsFilesystemSupported(mFsType)) { LOG(ERROR) << getId() << " unsupported filesystem " << mFsType; return -EIO; } @@ -140,18 +133,44 @@ status_t PublicVolume::doMount() { return -errno; } - if (mFsType == "vfat") { - if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_ROOT, - (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007, true)) { - PLOG(ERROR) << getId() << " failed to mount " << mDevPath; - return -EIO; - } - } else if (mFsType == "exfat") { - if (exfat::Mount(mDevPath, mRawPath, AID_ROOT, - (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007)) { - PLOG(ERROR) << getId() << " failed to mount " << mDevPath; - return -EIO; - } + int ret = 0; + if (mFsType == "exfat") { + ret = exfat::Check(mDevPath); + } else if (mFsType == "ext4") { + ret = ext4::Check(mDevPath, mRawPath); + } else if (mFsType == "f2fs") { + ret = f2fs::Check(mDevPath); + } else if (mFsType == "ntfs") { + ret = ntfs::Check(mDevPath); + } else if (mFsType == "vfat") { + ret = vfat::Check(mDevPath); + } else { + LOG(WARNING) << getId() << " unsupported filesystem check, skipping"; + } + if (ret) { + LOG(ERROR) << getId() << " failed filesystem check"; + return -EIO; + } + + if (mFsType == "exfat") { + ret = exfat::Mount(mDevPath, mRawPath, AID_ROOT, + (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007); + } else if (mFsType == "ext4") { + ret = ext4::Mount(mDevPath, mRawPath, false, false, true); + } else if (mFsType == "f2fs") { + ret = f2fs::Mount(mDevPath, mRawPath); + } else if (mFsType == "ntfs") { + ret = ntfs::Mount(mDevPath, mRawPath, AID_ROOT, + (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007); + } else if (mFsType == "vfat") { + ret = vfat::Mount(mDevPath, mRawPath, false, false, false, AID_ROOT, + (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007, true); + } else { + ret = ::mount(mDevPath.c_str(), mRawPath.c_str(), mFsType.c_str(), 0, NULL); + } + if (ret) { + PLOG(ERROR) << getId() << " failed to mount " << mDevPath; + return -EIO; } if (getMountFlags() & MountFlags::kPrimary) { @@ -337,7 +356,7 @@ status_t PublicVolume::doFormat(const std::string& fsType) { useVfat = false; } - if (!useVfat && !useExfat) { + if (!IsFilesystemSupported(fsType) && !useVfat && !useExfat) { LOG(ERROR) << "Unsupported filesystem " << fsType; return -EINVAL; } @@ -350,6 +369,16 @@ status_t PublicVolume::doFormat(const std::string& fsType) { res = vfat::Format(mDevPath, 0); } else if (useExfat) { res = exfat::Format(mDevPath); + } else if (fsType == "ext4") { + res = ext4::Format(mDevPath, 0, mRawPath); + } else if (fsType == "f2fs") { + res = f2fs::Format(mDevPath); + } else if (fsType == "ntfs") { + res = ntfs::Format(mDevPath); + } else { + LOG(ERROR) << getId() << " unrecognized filesystem " << fsType; + res = -1; + errno = EIO; } if (res != OK) {