Add basic exFAT support.
Several partners have been requesting exFAT support. Android doesn't natively support exFAT, but we're at least willing to try mounting an exFAT filesystem if we detect the Linux kernel supports it, and if helper binaries are present. This CL is simple scaffolding, and it provides no actual implementation of exFAT. Test: builds, boots Bug: 67822822 Change-Id: Id4f8ec3967b32de6e1c0e3c4b47fe6e43a6291ab
This commit is contained in:
parent
a8b6225578
commit
37ba125205
5 changed files with 177 additions and 19 deletions
|
@ -115,6 +115,7 @@ cc_library_static {
|
|||
"VolumeManager.cpp",
|
||||
"authorization_set.cpp",
|
||||
"cryptfs.cpp",
|
||||
"fs/Exfat.cpp",
|
||||
"fs/Ext4.cpp",
|
||||
"fs/F2fs.cpp",
|
||||
"fs/Vfat.cpp",
|
||||
|
|
97
fs/Exfat.cpp
Normal file
97
fs/Exfat.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
|
||||
#include <logwrap/logwrap.h>
|
||||
|
||||
#include "Exfat.h"
|
||||
#include "Utils.h"
|
||||
|
||||
using android::base::StringPrintf;
|
||||
|
||||
namespace android {
|
||||
namespace vold {
|
||||
namespace exfat {
|
||||
|
||||
static const char* kMkfsPath = "/system/bin/mkfs.exfat";
|
||||
static const char* kFsckPath = "/system/bin/fsck.exfat";
|
||||
|
||||
bool IsSupported() {
|
||||
return access(kMkfsPath, X_OK) == 0 && 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);
|
||||
|
||||
int rc = ForkExecvp(cmd, 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) {
|
||||
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;
|
||||
}
|
||||
|
||||
status_t Format(const std::string& source) {
|
||||
std::vector<std::string> cmd;
|
||||
cmd.push_back(kMkfsPath);
|
||||
cmd.push_back("-n");
|
||||
cmd.push_back("android");
|
||||
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 exfat
|
||||
} // namespace vold
|
||||
} // namespace android
|
39
fs/Exfat.h
Normal file
39
fs/Exfat.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2018 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_EXFAT_H
|
||||
#define ANDROID_VOLD_EXFAT_H
|
||||
|
||||
#include <utils/Errors.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
namespace vold {
|
||||
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);
|
||||
status_t Format(const std::string& source);
|
||||
|
||||
} // namespace exfat
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
#endif
|
|
@ -365,6 +365,7 @@ status_t Disk::readPartitions() {
|
|||
|
||||
switch (type) {
|
||||
case 0x06: // FAT16
|
||||
case 0x07: // HPFS/NTFS/exFAT
|
||||
case 0x0b: // W95 FAT32 (LBA)
|
||||
case 0x0c: // W95 FAT32 (LBA)
|
||||
case 0x0e: // W95 FAT16 (LBA)
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "fs/Vfat.h"
|
||||
#include "PublicVolume.h"
|
||||
#include "Utils.h"
|
||||
#include "VolumeManager.h"
|
||||
#include "fs/Exfat.h"
|
||||
#include "fs/Vfat.h"
|
||||
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/logging.h>
|
||||
|
@ -93,18 +94,22 @@ status_t PublicVolume::doDestroy() {
|
|||
}
|
||||
|
||||
status_t PublicVolume::doMount() {
|
||||
// TODO: expand to support mounting other filesystems
|
||||
readMetadata();
|
||||
|
||||
if (mFsType != "vfat") {
|
||||
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
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 {
|
||||
LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// Use UUID as stable name, if available
|
||||
std::string stableName = getId();
|
||||
|
@ -130,11 +135,18 @@ status_t PublicVolume::doMount() {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
if (vfat::Mount(mDevPath, mRawPath, false, false, false,
|
||||
AID_MEDIA_RW, AID_MEDIA_RW, 0007, true)) {
|
||||
if (mFsType == "vfat") {
|
||||
if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007,
|
||||
true)) {
|
||||
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
|
||||
return -EIO;
|
||||
}
|
||||
} else if (mFsType == "exfat") {
|
||||
if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) {
|
||||
PLOG(ERROR) << getId() << " failed to mount " << mDevPath;
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (getMountFlags() & MountFlags::kPrimary) {
|
||||
initAsecStage();
|
||||
|
@ -238,7 +250,7 @@ status_t PublicVolume::doUnmount() {
|
|||
}
|
||||
|
||||
status_t PublicVolume::doFormat(const std::string& fsType) {
|
||||
if (fsType == "vfat" || fsType == "auto") {
|
||||
if ((fsType == "vfat" || fsType == "auto") && vfat::IsSupported()) {
|
||||
if (WipeBlockDevice(mDevPath) != OK) {
|
||||
LOG(WARNING) << getId() << " failed to wipe";
|
||||
}
|
||||
|
@ -246,6 +258,14 @@ status_t PublicVolume::doFormat(const std::string& fsType) {
|
|||
LOG(ERROR) << getId() << " failed to format";
|
||||
return -errno;
|
||||
}
|
||||
} else if ((fsType == "exfat" || fsType == "auto") && exfat::IsSupported()) {
|
||||
if (WipeBlockDevice(mDevPath) != OK) {
|
||||
LOG(WARNING) << getId() << " failed to wipe";
|
||||
}
|
||||
if (exfat::Format(mDevPath)) {
|
||||
LOG(ERROR) << getId() << " failed to format";
|
||||
return -errno;
|
||||
}
|
||||
} else {
|
||||
LOG(ERROR) << "Unsupported filesystem " << fsType;
|
||||
return -EINVAL;
|
||||
|
|
Loading…
Reference in a new issue