diff --git a/Android.mk b/Android.mk
index f5cd54d..4bab604 100644
--- a/Android.mk
+++ b/Android.mk
@@ -8,8 +8,9 @@ common_src_files := \
NetlinkManager.cpp \
NetlinkHandler.cpp \
Process.cpp \
- Ext4.cpp \
- Fat.cpp \
+ fs/Ext4.cpp \
+ fs/F2fs.cpp \
+ fs/Vfat.cpp \
Loop.cpp \
Devmapper.cpp \
ResponseCode.cpp \
diff --git a/CommandListener.cpp b/CommandListener.cpp
index 2bfd58c..1f89b6a 100644
--- a/CommandListener.cpp
+++ b/CommandListener.cpp
@@ -223,15 +223,16 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
return sendGenericOkFail(cli, vol->unmount());
- } else if (cmd == "format" && argc > 2) {
- // format [volId]
+ } else if (cmd == "format" && argc > 3) {
+ // format [volId] [fsType|auto]
std::string id(argv[2]);
+ std::string fsType(argv[3]);
auto vol = vm->findVolume(id);
if (vol == nullptr) {
return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
}
- return sendGenericOkFail(cli, vol->format());
+ return sendGenericOkFail(cli, vol->format(fsType));
} else if (cmd == "move_storage" && argc > 3) {
// move_storage [fromVolId] [toVolId]
diff --git a/Disk.cpp b/Disk.cpp
index 5b5d769..a536dbf 100644
--- a/Disk.cpp
+++ b/Disk.cpp
@@ -136,7 +136,7 @@ void Disk::createPublicVolume(dev_t device) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
- vol->format();
+ vol->format("auto");
vol->destroy();
vol->setSilent(false);
}
@@ -168,7 +168,7 @@ void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) {
LOG(DEBUG) << "Device just partitioned; silently formatting";
vol->setSilent(true);
vol->create();
- vol->format();
+ vol->format("auto");
vol->destroy();
vol->setSilent(false);
}
diff --git a/PrivateVolume.cpp b/PrivateVolume.cpp
index ff2c7b3..a1bbb3b 100644
--- a/PrivateVolume.cpp
+++ b/PrivateVolume.cpp
@@ -14,7 +14,8 @@
* limitations under the License.
*/
-#include "Ext4.h"
+#include "fs/Ext4.h"
+#include "fs/F2fs.h"
#include "PrivateVolume.h"
#include "EmulatedVolume.h"
#include "Utils.h"
@@ -40,6 +41,8 @@ using android::base::StringPrintf;
namespace android {
namespace vold {
+static const unsigned int kMajorBlockMmc = 179;
+
PrivateVolume::PrivateVolume(dev_t device, const std::string& keyRaw) :
VolumeBase(Type::kPrivate), mRawDevice(device), mKeyRaw(keyRaw) {
setId(StringPrintf("private:%u,%u", major(device), minor(device)));
@@ -101,16 +104,36 @@ status_t PrivateVolume::doMount() {
return -EIO;
}
- int res = Ext4::check(mDmDevPath.c_str(), mPath.c_str());
- if (res == 0 || res == 1) {
- LOG(DEBUG) << getId() << " passed filesystem check";
- } else {
- PLOG(ERROR) << getId() << " failed filesystem check";
- return -EIO;
- }
+ if (mFsType == "ext4") {
+ int res = ext4::Check(mDmDevPath, mPath);
+ if (res == 0 || res == 1) {
+ LOG(DEBUG) << getId() << " passed filesystem check";
+ } else {
+ PLOG(ERROR) << getId() << " failed filesystem check";
+ return -EIO;
+ }
+
+ if (ext4::Mount(mDmDevPath, mPath, false, false, true)) {
+ PLOG(ERROR) << getId() << " failed to mount";
+ return -EIO;
+ }
+
+ } else if (mFsType == "f2fs") {
+ int res = f2fs::Check(mDmDevPath);
+ if (res == 0) {
+ LOG(DEBUG) << getId() << " passed filesystem check";
+ } else {
+ PLOG(ERROR) << getId() << " failed filesystem check";
+ return -EIO;
+ }
+
+ if (f2fs::Mount(mDmDevPath, mPath)) {
+ PLOG(ERROR) << getId() << " failed to mount";
+ return -EIO;
+ }
- if (Ext4::doMount(mDmDevPath.c_str(), mPath.c_str(), false, false, true)) {
- PLOG(ERROR) << getId() << " failed to mount";
+ } else {
+ LOG(ERROR) << getId() << " unsupported filesystem " << mFsType;
return -EIO;
}
@@ -124,6 +147,8 @@ status_t PrivateVolume::doMount() {
return -EIO;
}
+ // TODO: restorecon all the things!
+
// Create a new emulated volume stacked above us, it will automatically
// be destroyed during unmount
std::string mediaPath(mPath + "/media");
@@ -145,11 +170,33 @@ status_t PrivateVolume::doUnmount() {
return OK;
}
-status_t PrivateVolume::doFormat() {
- // TODO: change mountpoint once we have selinux labels
- if (Ext4::format(mDmDevPath.c_str(), 0, "/data")) {
- PLOG(ERROR) << getId() << " failed to format";
- return -EIO;
+status_t PrivateVolume::doFormat(const std::string& fsType) {
+ std::string resolvedFsType = fsType;
+ if (fsType == "auto") {
+ // For now, assume that all MMC devices are flash-based SD cards, and
+ // give everyone else ext4 because sysfs rotational isn't reliable.
+ if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) {
+ resolvedFsType = "f2fs";
+ } else {
+ resolvedFsType = "ext4";
+ }
+ LOG(DEBUG) << "Resolved auto to " << resolvedFsType;
+ }
+
+ if (resolvedFsType == "ext4") {
+ // TODO: change reported mountpoint once we have better selinux support
+ if (ext4::Format(mDmDevPath, 0, "/data")) {
+ PLOG(ERROR) << getId() << " failed to format";
+ return -EIO;
+ }
+ } else if (resolvedFsType == "f2fs") {
+ if (f2fs::Format(mDmDevPath)) {
+ PLOG(ERROR) << getId() << " failed to format";
+ return -EIO;
+ }
+ } else {
+ LOG(ERROR) << getId() << " unsupported filesystem " << fsType;
+ return -EINVAL;
}
return OK;
diff --git a/PrivateVolume.h b/PrivateVolume.h
index bd464e6..95b718d 100644
--- a/PrivateVolume.h
+++ b/PrivateVolume.h
@@ -45,7 +45,7 @@ protected:
status_t doDestroy() override;
status_t doMount() override;
status_t doUnmount() override;
- status_t doFormat() override;
+ status_t doFormat(const std::string& fsType) override;
status_t readMetadata();
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index 2b2c32b..9d6887d 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#include "Fat.h"
+#include "fs/Vfat.h"
#include "PublicVolume.h"
#include "Utils.h"
#include "VolumeManager.h"
@@ -94,7 +94,7 @@ status_t PublicVolume::doMount() {
// TODO: expand to support mounting other filesystems
readMetadata();
- if (Fat::check(mDevPath.c_str())) {
+ if (vfat::Check(mDevPath)) {
LOG(ERROR) << getId() << " failed filesystem check";
return -EIO;
}
@@ -119,7 +119,7 @@ status_t PublicVolume::doMount() {
return -errno;
}
- if (Fat::doMount(mDevPath.c_str(), mRawPath.c_str(), false, false, false,
+ 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;
@@ -200,11 +200,20 @@ status_t PublicVolume::doUnmount() {
return OK;
}
-status_t PublicVolume::doFormat() {
- if (Fat::format(mDevPath.c_str(), 0, true)) {
- LOG(ERROR) << getId() << " failed to format";
- return -errno;
+status_t PublicVolume::doFormat(const std::string& fsType) {
+ if (fsType == "vfat" || fsType == "auto") {
+ if (WipeBlockDevice(mDevPath) != OK) {
+ LOG(WARNING) << getId() << " failed to wipe";
+ }
+ if (vfat::Format(mDevPath, 0)) {
+ LOG(ERROR) << getId() << " failed to format";
+ return -errno;
+ }
+ } else {
+ LOG(ERROR) << "Unsupported filesystem " << fsType;
+ return -EINVAL;
}
+
return OK;
}
diff --git a/PublicVolume.h b/PublicVolume.h
index 45313ec..fd400f2 100644
--- a/PublicVolume.h
+++ b/PublicVolume.h
@@ -47,7 +47,7 @@ protected:
status_t doDestroy() override;
status_t doMount() override;
status_t doUnmount() override;
- status_t doFormat() override;
+ status_t doFormat(const std::string& fsType) override;
status_t readMetadata();
status_t initAsecStage();
diff --git a/Utils.cpp b/Utils.cpp
index 0b8ccfd..e06111a 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -18,6 +18,7 @@
#include "Utils.h"
#include "Process.h"
+#include
#include
#include
#include
@@ -39,6 +40,7 @@
#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
#endif
+using android::base::ReadFileToString;
using android::base::StringPrintf;
namespace android {
@@ -51,6 +53,8 @@ security_context_t sFsckUntrustedContext = nullptr;
static const char* kBlkidPath = "/system/bin/blkid";
+static const char* kProcFilesystems = "/proc/filesystems";
+
status_t CreateDeviceNode(const std::string& path, dev_t dev) {
const char* cpath = path.c_str();
status_t res = 0;
@@ -463,5 +467,47 @@ uint64_t GetTreeBytes(const std::string& path) {
}
}
+bool IsFilesystemSupported(const std::string& fsType) {
+ std::string supported;
+ if (!ReadFileToString(kProcFilesystems, &supported)) {
+ PLOG(ERROR) << "Failed to read supported filesystems";
+ return false;
+ }
+ return supported.find(fsType + "\n") != std::string::npos;
+}
+
+status_t WipeBlockDevice(const std::string& path) {
+ status_t res = -1;
+ const char* c_path = path.c_str();
+ unsigned long nr_sec = 0;
+ unsigned long long range[2];
+
+ int fd = TEMP_FAILURE_RETRY(open(c_path, O_RDWR | O_CLOEXEC));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path;
+ goto done;
+ }
+
+ if ((ioctl(fd, BLKGETSIZE, nr_sec)) == -1) {
+ PLOG(ERROR) << "Failed to determine size of " << path;
+ goto done;
+ }
+
+ range[0] = 0;
+ range[1] = (unsigned long long) nr_sec * 512;
+
+ LOG(INFO) << "About to discard " << range[1] << " on " << path;
+ if (ioctl(fd, BLKDISCARD, &range) == 0) {
+ LOG(INFO) << "Discard success on " << path;
+ res = 0;
+ } else {
+ PLOG(ERROR) << "Discard failure on " << path;
+ }
+
+done:
+ close(fd);
+ return res;
+}
+
} // namespace vold
} // namespace android
diff --git a/Utils.h b/Utils.h
index 6ad87ae..ab151aa 100644
--- a/Utils.h
+++ b/Utils.h
@@ -81,6 +81,11 @@ status_t StrToHex(const std::string& str, std::string& hex);
uint64_t GetFreeBytes(const std::string& path);
uint64_t GetTreeBytes(const std::string& path);
+bool IsFilesystemSupported(const std::string& fsType);
+
+/* Wipes contents of block device at given path */
+status_t WipeBlockDevice(const std::string& path);
+
} // namespace vold
} // namespace android
diff --git a/VolumeBase.cpp b/VolumeBase.cpp
index ca056a4..05a61ed 100644
--- a/VolumeBase.cpp
+++ b/VolumeBase.cpp
@@ -222,7 +222,7 @@ status_t VolumeBase::unmount() {
return res;
}
-status_t VolumeBase::format() {
+status_t VolumeBase::format(const std::string& fsType) {
if (mState == State::kMounted) {
unmount();
}
@@ -233,12 +233,12 @@ status_t VolumeBase::format() {
}
setState(State::kFormatting);
- status_t res = doFormat();
+ status_t res = doFormat(fsType);
setState(State::kUnmounted);
return res;
}
-status_t VolumeBase::doFormat() {
+status_t VolumeBase::doFormat(const std::string& fsType) {
return -ENOTSUP;
}
diff --git a/VolumeBase.h b/VolumeBase.h
index a9975f8..42b4d65 100644
--- a/VolumeBase.h
+++ b/VolumeBase.h
@@ -97,7 +97,7 @@ public:
status_t destroy();
status_t mount();
status_t unmount();
- status_t format();
+ status_t format(const std::string& fsType);
protected:
explicit VolumeBase(Type type);
@@ -106,7 +106,7 @@ protected:
virtual status_t doDestroy();
virtual status_t doMount() = 0;
virtual status_t doUnmount() = 0;
- virtual status_t doFormat();
+ virtual status_t doFormat(const std::string& fsType);
status_t setId(const std::string& id);
status_t setPath(const std::string& path);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index c34f169..9306363 100755
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -51,8 +51,8 @@
#include "NetlinkManager.h"
#include "ResponseCode.h"
#include "Loop.h"
-#include "Ext4.h"
-#include "Fat.h"
+#include "fs/Ext4.h"
+#include "fs/Vfat.h"
#include "Utils.h"
#include "Devmapper.h"
#include "Process.h"
@@ -725,9 +725,9 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha
}
if (usingExt4) {
- formatStatus = Ext4::format(dmDevice, numImgSectors, mountPoint);
+ formatStatus = android::vold::ext4::Format(dmDevice, numImgSectors, mountPoint);
} else {
- formatStatus = Fat::format(dmDevice, numImgSectors, 0);
+ formatStatus = android::vold::vfat::Format(dmDevice, numImgSectors);
}
if (formatStatus < 0) {
@@ -754,10 +754,11 @@ int VolumeManager::createAsec(const char *id, unsigned int numSectors, const cha
int mountStatus;
if (usingExt4) {
- mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
+ mountStatus = android::vold::ext4::Mount(dmDevice, mountPoint,
+ false, false, false);
} else {
- mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
- false);
+ mountStatus = android::vold::vfat::Mount(dmDevice, mountPoint,
+ false, false, false, ownerUid, 0, 0000, false);
}
if (mountStatus) {
@@ -916,7 +917,7 @@ int VolumeManager::resizeAsec(const char *id, unsigned numSectors, const char *k
*/
waitForDevMapper(dmDevice);
- if (Ext4::resize(dmDevice, numImgSectors)) {
+ if (android::vold::ext4::Resize(dmDevice, numImgSectors)) {
SLOGE("Unable to resize %s (%s)", id, strerror(errno));
if (cleanupDm) {
Devmapper::destroy(idHash);
@@ -973,9 +974,11 @@ int VolumeManager::finalizeAsec(const char *id) {
int result = 0;
if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
- result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
+ result = android::vold::ext4::Mount(loopDevice, mountPoint,
+ true, true, true);
} else {
- result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
+ result = android::vold::vfat::Mount(loopDevice, mountPoint,
+ true, true, true, 0, 0, 0227, false);
}
if (result) {
@@ -1039,7 +1042,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f
return 0;
}
- int ret = Ext4::doMount(loopDevice, mountPoint,
+ int ret = android::vold::ext4::Mount(loopDevice, mountPoint,
false /* read-only */,
true /* remount */,
false /* executable */);
@@ -1101,7 +1104,7 @@ int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* f
result |= -1;
}
- result |= Ext4::doMount(loopDevice, mountPoint,
+ result |= android::vold::ext4::Mount(loopDevice, mountPoint,
true /* read-only */,
true /* remount */,
true /* execute */);
@@ -1537,9 +1540,11 @@ int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid, bool
int result;
if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
- result = Ext4::doMount(dmDevice, mountPoint, readOnly, false, readOnly);
+ result = android::vold::ext4::Mount(dmDevice, mountPoint,
+ readOnly, false, readOnly);
} else {
- result = Fat::doMount(dmDevice, mountPoint, readOnly, false, readOnly, ownerUid, 0, 0222, false);
+ result = android::vold::vfat::Mount(dmDevice, mountPoint,
+ readOnly, false, readOnly, ownerUid, 0, 0222, false);
}
if (result) {
@@ -1628,8 +1633,8 @@ int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
*/
waitForDevMapper(dmDevice);
- if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
- 0227, false)) {
+ if (android::vold::vfat::Mount(dmDevice, mountPoint,
+ true, false, true, 0, ownerGid, 0227, false)) {
SLOGE("Image mount failed (%s)", strerror(errno));
if (cleanupDm) {
Devmapper::destroy(idHash);
diff --git a/Ext4.cpp b/fs/Ext4.cpp
similarity index 72%
rename from Ext4.cpp
rename to fs/Ext4.cpp
index a208eb5..3ae4159 100644
--- a/Ext4.cpp
+++ b/fs/Ext4.cpp
@@ -50,16 +50,26 @@
using android::base::StringPrintf;
+namespace android {
+namespace vold {
+namespace ext4 {
+
static const char* kResizefsPath = "/system/bin/resize2fs";
static const char* kMkfsPath = "/system/bin/make_ext4fs";
static const char* kFsckPath = "/system/bin/e2fsck";
-int Ext4::check(const char *fsPath, const char *mountPoint) {
+bool IsSupported() {
+ return access(kMkfsPath, X_OK) == 0
+ && access(kFsckPath, X_OK) == 0
+ && IsFilesystemSupported("ext4");
+}
+
+status_t Check(const std::string& source, const std::string& target) {
// The following is shamelessly borrowed from fs_mgr.c, so it should be
// kept in sync with any changes over there.
- char* blk_device = (char*) fsPath;
- char* target = (char*) mountPoint;
+ const char* c_source = source.c_str();
+ const char* c_target = target.c_str();
int status;
int ret;
@@ -79,17 +89,17 @@ int Ext4::check(const char *fsPath, const char *mountPoint) {
* filesytsem due to an error, e2fsck is still run to do a full check
* fix the filesystem.
*/
- ret = mount(blk_device, target, "ext4", tmpmnt_flags, tmpmnt_opts);
+ 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(target);
+ int result = umount(c_target);
if (result == 0) {
break;
}
- ALOGW("%s(): umount(%s)=%d: %s\n", __func__, target, result, strerror(errno));
+ ALOGW("%s(): umount(%s)=%d: %s\n", __func__, c_target, result, strerror(errno));
sleep(1);
}
}
@@ -100,61 +110,65 @@ int Ext4::check(const char *fsPath, const char *mountPoint) {
*/
if (access(kFsckPath, X_OK)) {
ALOGD("Not running %s on %s (executable not in system image)\n",
- kFsckPath, blk_device);
+ kFsckPath, c_source);
} else {
- ALOGD("Running %s on %s\n", kFsckPath, blk_device);
+ ALOGD("Running %s on %s\n", kFsckPath, c_source);
std::vector cmd;
cmd.push_back(kFsckPath);
cmd.push_back("-y");
- cmd.push_back(blk_device);
+ cmd.push_back(c_source);
- // Ext4 devices are currently always trusted
- return android::vold::ForkExecvp(cmd, android::vold::sFsckContext);
+ // ext4 devices are currently always trusted
+ return ForkExecvp(cmd, sFsckContext);
}
return 0;
}
-int Ext4::doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
- bool executable) {
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable) {
int rc;
unsigned long flags;
+ const char* c_source = source.c_str();
+ const char* c_target = target.c_str();
+
flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
flags |= (executable ? 0 : MS_NOEXEC);
flags |= (ro ? MS_RDONLY : 0);
flags |= (remount ? MS_REMOUNT : 0);
- rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+ rc = mount(c_source, c_target, "ext4", flags, NULL);
if (rc && errno == EROFS) {
- SLOGE("%s appears to be a read only filesystem - retrying mount RO", fsPath);
+ SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
flags |= MS_RDONLY;
- rc = mount(fsPath, mountPoint, "ext4", flags, NULL);
+ rc = mount(c_source, c_target, "ext4", flags, NULL);
}
return rc;
}
-int Ext4::resize(const char *fspath, unsigned int numSectors) {
+status_t Resize(const std::string& source, unsigned int numSectors) {
std::vector cmd;
cmd.push_back(kResizefsPath);
cmd.push_back("-f");
- cmd.push_back(fspath);
+ cmd.push_back(source);
cmd.push_back(StringPrintf("%u", numSectors));
- return android::vold::ForkExecvp(cmd);
+ return ForkExecvp(cmd);
}
-int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountpoint) {
+status_t Format(const std::string& source, unsigned int numSectors,
+ const std::string& target) {
std::vector cmd;
cmd.push_back(kMkfsPath);
cmd.push_back("-J");
cmd.push_back("-a");
- cmd.push_back(mountpoint);
+ cmd.push_back(target);
if (numSectors) {
cmd.push_back("-l");
@@ -163,7 +177,11 @@ int Ext4::format(const char *fsPath, unsigned int numSectors, const char *mountp
// Always generate a real UUID
cmd.push_back("-u");
- cmd.push_back(fsPath);
+ cmd.push_back(source);
- return android::vold::ForkExecvp(cmd);
+ return ForkExecvp(cmd);
}
+
+} // namespace ext4
+} // namespace vold
+} // namespace android
diff --git a/fs/Ext4.h b/fs/Ext4.h
new file mode 100644
index 0000000..a5efa74
--- /dev/null
+++ b/fs/Ext4.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2012 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_EXT4_H
+#define ANDROID_VOLD_EXT4_H
+
+#include
+
+#include
+
+namespace android {
+namespace vold {
+namespace ext4 {
+
+bool IsSupported();
+
+status_t Check(const std::string& source, const std::string& target);
+status_t Mount(const std::string& source, const std::string& target, bool ro,
+ bool remount, bool executable);
+status_t Format(const std::string& source, unsigned int numSectors,
+ const std::string& target);
+status_t Resize(const std::string& source, unsigned int numSectors);
+
+} // namespace ext4
+} // namespace vold
+} // namespace android
+
+#endif
diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp
new file mode 100644
index 0000000..b947822
--- /dev/null
+++ b/fs/F2fs.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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 "F2fs.h"
+#include "Utils.h"
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+using android::base::StringPrintf;
+
+namespace android {
+namespace vold {
+namespace f2fs {
+
+static const char* kMkfsPath = "/system/bin/make_f2fs";
+static const char* kFsckPath = "/system/bin/fsck.f2fs";
+
+bool IsSupported() {
+ return access(kMkfsPath, X_OK) == 0
+ && access(kFsckPath, X_OK) == 0
+ && IsFilesystemSupported("f2fs");
+}
+
+status_t Check(const std::string& source) {
+ std::vector cmd;
+ cmd.push_back(kFsckPath);
+ cmd.push_back("-f");
+ cmd.push_back(source);
+
+ // f2fs devices are currently always trusted
+ return ForkExecvp(cmd, sFsckContext);
+}
+
+status_t Mount(const std::string& source, const std::string& target) {
+ const char* c_source = source.c_str();
+ const char* c_target = target.c_str();
+ unsigned long flags = MS_NOATIME | MS_NODEV | MS_NOSUID | MS_DIRSYNC;
+
+ int res = mount(c_source, c_target, "f2fs", flags, NULL);
+ if (res != 0) {
+ PLOG(ERROR) << "Failed to mount " << source;
+ if (errno == EROFS) {
+ res = mount(c_source, c_target, "f2fs", flags | MS_RDONLY, NULL);
+ if (res != 0) {
+ PLOG(ERROR) << "Failed to mount read-only " << source;
+ }
+ }
+ }
+
+ return res;
+}
+
+status_t Format(const std::string& source) {
+ std::vector cmd;
+ cmd.push_back(kMkfsPath);
+ cmd.push_back(source);
+
+ return ForkExecvp(cmd);
+}
+
+} // namespace f2fs
+} // namespace vold
+} // namespace android
diff --git a/Ext4.h b/fs/F2fs.h
similarity index 54%
rename from Ext4.h
rename to fs/F2fs.h
index 55672af..f710212 100644
--- a/Ext4.h
+++ b/fs/F2fs.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -14,18 +14,25 @@
* limitations under the License.
*/
-#ifndef _EXT4_H
-#define _EXT4_H
+#ifndef ANDROID_VOLD_F2FS_H
+#define ANDROID_VOLD_F2FS_H
-#include
+#include
-class Ext4 {
-public:
- static int check(const char *fsPath, const char *mountPoint);
- static int doMount(const char *fsPath, const char *mountPoint, bool ro, bool remount,
- bool executable);
- static int format(const char *fsPath, unsigned int numSectors, const char *mountpoint);
- static int resize(const char *fsPath, unsigned int numSectors);
-};
+#include
+
+namespace android {
+namespace vold {
+namespace f2fs {
+
+bool IsSupported();
+
+status_t Check(const std::string& source);
+status_t Mount(const std::string& source, const std::string& target);
+status_t Format(const std::string& source);
+
+} // namespace f2fs
+} // namespace vold
+} // namespace android
#endif
diff --git a/Fat.cpp b/fs/Vfat.cpp
similarity index 73%
rename from Fat.cpp
rename to fs/Vfat.cpp
index 873088d..faff763 100644
--- a/Fat.cpp
+++ b/fs/Vfat.cpp
@@ -45,16 +45,26 @@
#include
-#include "Fat.h"
+#include "Vfat.h"
#include "Utils.h"
#include "VoldUtil.h"
using android::base::StringPrintf;
+namespace android {
+namespace vold {
+namespace vfat {
+
static const char* kMkfsPath = "/system/bin/newfs_msdos";
static const char* kFsckPath = "/system/bin/fsck_msdos";
-int Fat::check(const char *fsPath) {
+bool IsSupported() {
+ return access(kMkfsPath, X_OK) == 0
+ && 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;
@@ -67,10 +77,10 @@ int Fat::check(const char *fsPath) {
cmd.push_back(kFsckPath);
cmd.push_back("-p");
cmd.push_back("-f");
- cmd.push_back(fsPath);
+ cmd.push_back(source);
// Fat devices are currently always untrusted
- rc = android::vold::ForkExecvp(cmd, android::vold::sFsckUntrustedContext);
+ rc = ForkExecvp(cmd, sFsckUntrustedContext);
if (rc < 0) {
SLOGE("Filesystem check failed due to logwrap error");
@@ -108,13 +118,16 @@ int Fat::check(const char *fsPath) {
return 0;
}
-int Fat::doMount(const char *fsPath, const char *mountPoint,
- bool ro, bool remount, bool executable,
- int ownerUid, int ownerGid, int permMask, bool createLost) {
+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;
flags |= (executable ? 0 : MS_NOEXEC);
@@ -139,17 +152,17 @@ int Fat::doMount(const char *fsPath, const char *mountPoint,
"utf8,uid=%d,gid=%d,fmask=%o,dmask=%o,shortname=mixed",
ownerUid, ownerGid, permMask, permMask);
- rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
+ 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", fsPath);
+ SLOGE("%s appears to be a read only filesystem - retrying mount RO", c_source);
flags |= MS_RDONLY;
- rc = mount(fsPath, mountPoint, "vfat", flags, mountData);
+ rc = mount(c_source, c_target, "vfat", flags, mountData);
}
if (rc == 0 && createLost) {
char *lost_path;
- asprintf(&lost_path, "%s/LOST.DIR", mountPoint);
+ 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
@@ -165,11 +178,7 @@ int Fat::doMount(const char *fsPath, const char *mountPoint,
return rc;
}
-int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) {
- if (wipe) {
- Fat::wipe(fsPath, numSectors);
- }
-
+status_t Format(const std::string& source, unsigned int numSectors) {
std::vector cmd;
cmd.push_back(kMkfsPath);
cmd.push_back("-F");
@@ -185,9 +194,9 @@ int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) {
cmd.push_back(StringPrintf("%u", numSectors));
}
- cmd.push_back(fsPath);
+ cmd.push_back(source);
- int rc = android::vold::ForkExecvp(cmd);
+ int rc = ForkExecvp(cmd);
if (rc < 0) {
SLOGE("Filesystem format failed due to logwrap error");
errno = EIO;
@@ -205,36 +214,6 @@ int Fat::format(const char *fsPath, unsigned int numSectors, bool wipe) {
return 0;
}
-void Fat::wipe(const char *fsPath, unsigned int numSectors) {
- unsigned long long range[2];
-
- int fd = open(fsPath, O_RDWR | O_CLOEXEC);
- if (fd == -1) {
- SLOGE("Fat wipe failed to open device %s", fsPath);
- return;
- }
-
- if (numSectors == 0) {
- unsigned long nr_sec;
- get_blkdev_size(fd, &nr_sec);
- if (nr_sec > UINT32_MAX) {
- SLOGE("Too many sectors for FAT: %ld", nr_sec);
- close(fd);
- return;
- }
- numSectors = nr_sec;
- }
- if (numSectors == 0) {
- SLOGE("Fat wipe failed to determine size of %s", fsPath);
- close(fd);
- return;
- }
- range[0] = 0;
- range[1] = (unsigned long long)numSectors * 512;
- if (ioctl(fd, BLKDISCARD, &range) < 0) {
- SLOGE("Fat wipe failed to discard blocks on %s", fsPath);
- } else {
- SLOGI("Fat wipe %d sectors on %s succeeded", numSectors, fsPath);
- }
- close(fd);
-}
+} // namespace vfat
+} // namespace vold
+} // namespace android
diff --git a/Fat.h b/fs/Vfat.h
similarity index 54%
rename from Fat.h
rename to fs/Vfat.h
index 19614d1..306c7db 100644
--- a/Fat.h
+++ b/fs/Vfat.h
@@ -14,22 +14,27 @@
* limitations under the License.
*/
-#ifndef _FAT_H
-#define _FAT_H
-
-#include
-
-class Fat {
-public:
- static int check(const char *fsPath);
- static int doMount(const char *fsPath, const char *mountPoint,
- bool ro, bool remount, bool executable,
- int ownerUid, int ownerGid, int permMask,
- bool createLost);
- static int format(const char *fsPath, unsigned int numSectors, bool wipe);
-
-private:
- static void wipe(const char *fsPath, unsigned int numSectors);
-};
+#ifndef ANDROID_VOLD_VFAT_H
+#define ANDROID_VOLD_VFAT_H
+
+#include
+
+#include
+
+namespace android {
+namespace vold {
+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);
+status_t Format(const std::string& source, unsigned int numSectors);
+
+} // namespace vfat
+} // namespace vold
+} // namespace android
#endif
diff --git a/main.cpp b/main.cpp
index 290093f..abdff9f 100644
--- a/main.cpp
+++ b/main.cpp
@@ -55,6 +55,11 @@ int main(int argc, char** argv) {
LOG(INFO) << "Vold 3.0 (the awakening) firing up";
+ LOG(VERBOSE) << "Detected support for:"
+ << (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
+ << (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
+ << (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
+
VolumeManager *vm;
CommandListener *cl;
CryptCommandListener *ccl;