vold: Add support for ISO9660/UDF CD-ROM
This commit is squash of the following commits, with improvements:
Author: Yumi Yukimura <me.cafebabe@gmail.com>
Date: Thu Jul 25 03:38:40 2024 +0800
vold: Handle USB CDROM that has both filesystem and partition table
* Unlike SATA CDROM, USB CDROM has the same major and minor number,
and the same block device name (sdX) as USB Disk.
* For SATA CDROM, sgdisk_read() would fail, but for USB CDROM it
won't fail if partition table is found.
* ISO image generated by grub-mkrescue is in such format.
Author: Chih-Wei Huang <cwhuang@linux.org.tw>
Date: Sat Mar 25 16:46:42 2017 +0000
vold3: support UDF (Universal Disk Format)
Refer to https://en.wikipedia.org/wiki/Universal_Disk_Format.
[cafebabe: Apply fixups suggested by Luca Stefani]
Author: Chih-Wei Huang <cwhuang@linux.org.tw>
Date: Sat Mar 25 16:45:41 2017 +0000
vold3: auto mount CDROM
Luo Chunbo's ISO9660 support (commit 133632d5) is not complete. Still
need to handle block devices with major number of CDROM.
[cafebabe: Refactor in PublicVolume::doMount()]
Author: Luo Chunbo <luochunbo@jidemail.com>
Date: Wed May 25 16:16:48 2016 +0800
vold: ISO9660 support
Ref: T7691
[cafebabe: Remove MS_DIRSYNC and utf8 flags which are "Invalid argument", Refactor iso9660::Mount() (Suggested edit by Luca Stefani)]
Signed-off-by: Luo Chunbo <luochunbo@jidemail.com>
Change-Id: Ideef1064e509cfc5e3bc4cfe9d41cc8149767e6c
diff --git a/Android.bp b/Android.bp
index 9b4de31..d8baf61 100644
--- a/Android.bp
+++ b/Android.bp
@@ -149,6 +149,7 @@
"fs/Exfat.cpp",
"fs/Ext4.cpp",
"fs/F2fs.cpp",
+ "fs/Iso9660.cpp",
"fs/Ntfs.cpp",
"fs/Vfat.cpp",
"model/Disk.cpp",
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index d3c349f..36d2c66 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -104,6 +104,7 @@
/* 512MiB is large enough for testing purposes */
static const unsigned int kSizeVirtualDisk = 536870912;
+static const unsigned int kMajorBlockCdrom = 11;
static const unsigned int kMajorBlockMmc = 179;
using ScanProcCallback = bool(*)(uid_t uid, pid_t pid, int nsFd, const char* name, void* params);
@@ -225,6 +226,8 @@
int flags = source->getFlags();
if (major == kMajorBlockMmc || IsVirtioBlkDevice(major)) {
flags |= android::vold::Disk::Flags::kSd;
+ } else if (major == kMajorBlockCdrom) {
+ flags |= android::vold::Disk::Flags::kCdrom;
} else {
flags |= android::vold::Disk::Flags::kUsb;
}
diff --git a/fs/Iso9660.cpp b/fs/Iso9660.cpp
new file mode 100644
index 0000000..44f6f21
--- /dev/null
+++ b/fs/Iso9660.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 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 <stdio.h>
+#include <sys/mount.h>
+#include <utils/Errors.h>
+#include <android-base/stringprintf.h>
+#include "Iso9660.h"
+#include "Utils.h"
+
+namespace android {
+namespace vold {
+namespace iso9660 {
+
+bool IsIso9660Supported() {
+ return IsFilesystemSupported("iso9660");
+}
+
+bool IsUdfSupported() {
+ return IsFilesystemSupported("udf");
+}
+
+status_t Mount(const std::string& source, const std::string& target,
+ int ownerUid, int ownerGid ) {
+ int mountFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID | MS_RDONLY;
+ auto mountData = android::base::StringPrintf("uid=%d,gid=%d", ownerUid, ownerGid);
+ if (mount(source.c_str(), target.c_str(), "iso9660", mountFlags, mountData.c_str()) == 0) {
+ return 0;
+ }
+ if (mount(source.c_str(), target.c_str(), "udf", mountFlags, mountData.c_str()) == 0) {
+ return 0;
+ }
+ return -1;
+}
+
+} // namespace iso9660
+} // namespace vold
+} // namespace android
diff --git a/fs/Iso9660.h b/fs/Iso9660.h
new file mode 100644
index 0000000..b01000c
--- /dev/null
+++ b/fs/Iso9660.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2008 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 _ISO9660_H
+#define _ISO9660_H
+
+#include <string>
+
+namespace android {
+namespace vold {
+namespace iso9660 {
+
+bool IsIso9660Supported();
+bool IsUdfSupported();
+status_t Mount(const std::string& source, const std::string& target,
+ int ownerUid, int ownerGid );
+
+} // namespace iso9660
+} // namespace vold
+} // namespace android
+
+
+#endif
diff --git a/main.cpp b/main.cpp
index 1eace14..8956cd5 100644
--- a/main.cpp
+++ b/main.cpp
@@ -76,7 +76,9 @@
<< (android::vold::IsFilesystemSupported("exfat") ? " exfat" : "")
<< (android::vold::IsFilesystemSupported("ext4") ? " ext4" : "")
<< (android::vold::IsFilesystemSupported("f2fs") ? " f2fs" : "")
+ << (android::vold::IsFilesystemSupported("iso9660") ? " iso9660" : "")
<< (android::vold::IsFilesystemSupported("ntfs") ? " ntfs" : "")
+ << (android::vold::IsFilesystemSupported("udf") ? " udf" : "")
<< (android::vold::IsFilesystemSupported("vfat") ? " vfat" : "");
VolumeManager* vm;
diff --git a/model/Disk.cpp b/model/Disk.cpp
index 9576107..1a8a7ac 100644
--- a/model/Disk.cpp
+++ b/model/Disk.cpp
@@ -75,6 +75,7 @@
static const unsigned int kMajorBlockMmc = 179;
static const unsigned int kMajorBlockDynamicMin = 234;
static const unsigned int kMajorBlockDynamicMax = 512;
+static const unsigned int kMajorBlockCdrom = 11;
static const char* kGptBasicData = "EBD0A0A2-B9E5-4433-87C0-68B6B72699C7";
static const char* kGptLinuxFilesystem = "0FC63DAF-8483-4772-8E79-3D69D8477DE4";
@@ -257,6 +258,9 @@
mLabel = "Virtual";
break;
}
+ case kMajorBlockCdrom:
+ LOG(DEBUG) << "Found a CDROM: " << mSysPath;
+ FALLTHROUGH_INTENDED;
// clang-format off
case kMajorBlockScsiA: case kMajorBlockScsiB: case kMajorBlockScsiC:
case kMajorBlockScsiD: case kMajorBlockScsiE: case kMajorBlockScsiF:
@@ -330,6 +334,12 @@
}
status_t Disk::readPartitions() {
+ std::vector<std::string> cmd;
+ std::vector<std::string> output;
+ Table table = Table::kUnknown;
+ bool foundParts = false;
+ status_t res;
+
int maxMinors = getMaxMinors();
if (maxMinors < 0) {
return -ENOTSUP;
@@ -343,15 +353,23 @@
destroyAllVolumes();
+ if (!maxMinors) {
+ std::string cdFsType, cdUnused;
+ if (ReadMetadataUntrusted(mDevPath, &cdFsType, &cdUnused, &cdUnused) == OK) {
+ if (cdFsType == "iso9660" || cdFsType == "udf") {
+ LOG(INFO) << "Detect " << cdFsType;
+ goto treat_disk_as_partition;
+ }
+ }
+ }
+
// Parse partition table
- std::vector<std::string> cmd;
cmd.push_back(kSgdiskPath);
cmd.push_back("--android-dump");
cmd.push_back(mDevPath);
- std::vector<std::string> output;
- status_t res = ForkExecvp(cmd, &output);
+ res = ForkExecvp(cmd, &output);
if (res != OK) {
LOG(WARNING) << "sgdisk failed to scan " << mDevPath;
@@ -362,8 +380,6 @@
return res;
}
- Table table = Table::kUnknown;
- bool foundParts = false;
for (const auto& line : output) {
auto split = android::base::Split(line, kSgdiskToken);
auto it = split.begin();
@@ -426,6 +442,7 @@
}
}
+treat_disk_as_partition:
// Ugly last ditch effort, treat entire disk as partition
if (table == Table::kUnknown || !foundParts) {
LOG(WARNING) << mId << " has unknown partition table; trying entire device";
@@ -640,6 +657,9 @@
// Per Documentation/devices.txt this is static
return 15;
}
+ case kMajorBlockCdrom: {
+ return 0;
+ }
case kMajorBlockMmc: {
// Per Documentation/devices.txt this is dynamic
std::string tmp;
diff --git a/model/Disk.h b/model/Disk.h
index 7e90c85..4c78532 100644
--- a/model/Disk.h
+++ b/model/Disk.h
@@ -61,6 +61,8 @@
kStubVisible = 1 << 6,
/* Flag that disk is non-removable */
kNonRemovable = 1 << 7,
+ /* Flag that disk is CDROM */
+ kCdrom = 1 << 8,
};
const std::string& getId() const { return mId; }
diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp
index b4bd43e..bf7aaa6 100644
--- a/model/PublicVolume.cpp
+++ b/model/PublicVolume.cpp
@@ -22,6 +22,7 @@
#include "fs/Exfat.h"
#include "fs/Ext4.h"
#include "fs/F2fs.h"
+#include "fs/Iso9660.h"
#include "fs/Ntfs.h"
#include "fs/Vfat.h"
@@ -67,6 +68,12 @@
status_t PublicVolume::readMetadata() {
status_t res = ReadMetadataUntrusted(mDevPath, &mFsType, &mFsUuid, &mFsLabel);
+ // iso9660 has no UUID, we use label as UUID
+ if ((mFsType == "iso9660" || mFsType == "udf") && mFsUuid.empty() && !mFsLabel.empty()) {
+ std::replace(mFsLabel.begin(), mFsLabel.end(), ' ', '_');
+ mFsUuid = mFsLabel;
+ }
+
auto listener = getListener();
if (listener) listener->onVolumeMetadataChanged(getId(), mFsType, mFsUuid, mFsLabel);
@@ -154,6 +161,8 @@
ret = ntfs::Check(mDevPath);
} else if (mFsType == "vfat") {
ret = vfat::Check(mDevPath);
+ } else if (mFsType == "iso9660" || mFsType == "udf") {
+ // do nothing
} else {
LOG(WARNING) << getId() << " unsupported filesystem check, skipping";
}
@@ -170,6 +179,8 @@
false, true);
} else if (mFsType == "f2fs") {
ret = f2fs::Mount(mDevPath, mRawPath, mMntOpts, false, true);
+ } else if (mFsType == "iso9660" || mFsType == "udf") {
+ ret = iso9660::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW);
} else if (mFsType == "ntfs") {
ret = ntfs::Mount(mDevPath, mRawPath, AID_ROOT,
(isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007);