From 148892f1025dfd8c2e5b81a282b7d58ade373f7f Mon Sep 17 00:00:00 2001 From: Thierry Crozat Date: Sun, 19 Mar 2023 23:30:11 +0000 Subject: [PATCH] BACKENDS: Add possibility to specify virtual drive in ChRootFilesystemFactory It allows to get access to additional directories outside of the sandbox root. This is used on iOS to access files in the app bundle. --- backends/fs/chroot/chroot-fs-factory.cpp | 17 ++++++++++++++- backends/fs/chroot/chroot-fs-factory.h | 3 +++ backends/fs/chroot/chroot-fs.cpp | 25 ++++++++++++++--------- backends/fs/chroot/chroot-fs.h | 5 +++-- backends/platform/ios7/ios7_osys_main.cpp | 11 +++++++++- 5 files changed, 47 insertions(+), 14 deletions(-) diff --git a/backends/fs/chroot/chroot-fs-factory.cpp b/backends/fs/chroot/chroot-fs-factory.cpp index 8190e16bd27..7042a579941 100644 --- a/backends/fs/chroot/chroot-fs-factory.cpp +++ b/backends/fs/chroot/chroot-fs-factory.cpp @@ -47,16 +47,31 @@ AbstractFSNode *ChRootFilesystemFactory::makeCurrentDirectoryFileNode() const { return NULL; } - if (Common::String(buf).hasPrefix(_root + Common::String("/"))) { + Common::String curPath(buf); + if (curPath.hasPrefix(_root + Common::String("/"))) { return new ChRootFilesystemNode(_root, buf + _root.size()); } + for (auto it = _virtualDrives.begin() ; it != _virtualDrives.end() ; ++it) { + if (curPath.hasPrefix(it->_value + Common::String("/"))) + return new ChRootFilesystemNode(it->_value, buf + it->_value.size(), it->_key); + } return new ChRootFilesystemNode(_root, "/"); } AbstractFSNode *ChRootFilesystemFactory::makeFileNodePath(const Common::String &path) const { assert(!path.empty()); + size_t driveEnd = path.findFirstOf('/'); + if (driveEnd != Common::String::npos && driveEnd > 0) { + auto it = _virtualDrives.find(path.substr(0, driveEnd)); + if (it != _virtualDrives.end()) + return new ChRootFilesystemNode(it->_value, path.substr(driveEnd), it->_key); + } return new ChRootFilesystemNode(_root, path); } +void ChRootFilesystemFactory::addVirtualDrive(const Common::String &name, const Common::String &path) { + _virtualDrives[name] = path; +} + #endif diff --git a/backends/fs/chroot/chroot-fs-factory.h b/backends/fs/chroot/chroot-fs-factory.h index 336a958a2c5..a9ad3e1dbae 100644 --- a/backends/fs/chroot/chroot-fs-factory.h +++ b/backends/fs/chroot/chroot-fs-factory.h @@ -37,9 +37,12 @@ public: AbstractFSNode *makeRootFileNode() const override; AbstractFSNode *makeCurrentDirectoryFileNode() const override; AbstractFSNode *makeFileNodePath(const Common::String &path) const override; + + void addVirtualDrive(const Common::String &name, const Common::String &path); private: const Common::String _root; + Common::StringMap _virtualDrives; }; #endif /* BACKENDS_FS_CHROOT_CHROOT_FS_FACTORY_H */ diff --git a/backends/fs/chroot/chroot-fs.cpp b/backends/fs/chroot/chroot-fs.cpp index efcea8b9d50..5629aebdb74 100644 --- a/backends/fs/chroot/chroot-fs.cpp +++ b/backends/fs/chroot/chroot-fs.cpp @@ -23,13 +23,15 @@ #include "backends/fs/chroot/chroot-fs.h" -ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *node) { +ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *node, const Common::String &drive) { _root = Common::normalizePath(root, '/'); + _drive = drive; _realNode = node; } -ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, const Common::String &path) { +ChRootFilesystemNode::ChRootFilesystemNode(const Common::String &root, const Common::String &path, const Common::String &drive) { _root = Common::normalizePath(root, '/'); + _drive = drive; _realNode = new POSIXFilesystemNode(addPathComponent(root, path)); } @@ -51,10 +53,9 @@ Common::String ChRootFilesystemNode::getName() const { Common::String ChRootFilesystemNode::getPath() const { Common::String path = _realNode->getPath(); - if (path.size() > _root.size()) { - return Common::String(path.c_str() + _root.size()); - } - return Common::String("/"); + if (path.size() > _root.size()) + return _drive + Common::String(path.c_str() + _root.size()); + return _drive + "/"; } bool ChRootFilesystemNode::isDirectory() const { @@ -66,11 +67,14 @@ bool ChRootFilesystemNode::isReadable() const { } bool ChRootFilesystemNode::isWritable() const { + // Assume virtual drives are not writable + if (!_drive.empty()) + return false; return _realNode->isWritable(); } AbstractFSNode *ChRootFilesystemNode::getChild(const Common::String &n) const { - return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getChild(n)); + return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getChild(n), _drive); } bool ChRootFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool hidden) const { @@ -80,15 +84,16 @@ bool ChRootFilesystemNode::getChildren(AbstractFSList &list, ListMode mode, bool } for (AbstractFSList::iterator i=tmp.begin(); i!=tmp.end(); ++i) { - list.push_back(new ChRootFilesystemNode(_root, (POSIXFilesystemNode *) *i)); + list.push_back(new ChRootFilesystemNode(_root, (POSIXFilesystemNode *) *i, _drive)); } return true; } AbstractFSNode *ChRootFilesystemNode::getParent() const { - if (getPath() == "/") return 0; - return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getParent()); + if (getPath() == _drive + "/") + return nullptr; + return new ChRootFilesystemNode(_root, (POSIXFilesystemNode *)_realNode->getParent(), _drive); } Common::SeekableReadStream *ChRootFilesystemNode::createReadStream() { diff --git a/backends/fs/chroot/chroot-fs.h b/backends/fs/chroot/chroot-fs.h index f2d8e7ab8ca..8d80a95769f 100644 --- a/backends/fs/chroot/chroot-fs.h +++ b/backends/fs/chroot/chroot-fs.h @@ -26,12 +26,13 @@ class ChRootFilesystemNode final : public AbstractFSNode { Common::String _root; + Common::String _drive; POSIXFilesystemNode *_realNode; - ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *); + ChRootFilesystemNode(const Common::String &root, POSIXFilesystemNode *, const Common::String &drive); public: - ChRootFilesystemNode(const Common::String &root, const Common::String &path); + ChRootFilesystemNode(const Common::String &root, const Common::String &path, const Common::String &drive = Common::String()); ~ChRootFilesystemNode() override; bool exists() const override; diff --git a/backends/platform/ios7/ios7_osys_main.cpp b/backends/platform/ios7/ios7_osys_main.cpp index 417882b127e..1ca10a81f23 100644 --- a/backends/platform/ios7/ios7_osys_main.cpp +++ b/backends/platform/ios7/ios7_osys_main.cpp @@ -97,7 +97,16 @@ OSystem_iOS7::OSystem_iOS7() : _touchpadModeEnabled = !iOS7_isBigDevice(); #ifdef IPHONE_SANDBOXED _chrootBasePath = iOS7_getDocumentsDir(); - _fsFactory = new ChRootFilesystemFactory(_chrootBasePath); + ChRootFilesystemFactory *chFsFactory = new ChRootFilesystemFactory(_chrootBasePath); + _fsFactory = chFsFactory; + // Add virtual drive for bundle path + CFURLRef fileUrl = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); + if (fileUrl) { + UInt8 buf[MAXPATHLEN]; + if (CFURLGetFileSystemRepresentation(fileUrl, true, buf, sizeof(buf))) + chFsFactory->addVirtualDrive("appbundle:", Common::String((const char *)buf)); + CFRelease(fileUrl); + } #else _fsFactory = new POSIXFilesystemFactory(); #endif