diff options
Diffstat (limited to 'backends/fs/posix/posix-fs.cpp')
| -rw-r--r-- | backends/fs/posix/posix-fs.cpp | 212 |
1 files changed, 109 insertions, 103 deletions
diff --git a/backends/fs/posix/posix-fs.cpp b/backends/fs/posix/posix-fs.cpp index 10782a9057..8dca78d82a 100644 --- a/backends/fs/posix/posix-fs.cpp +++ b/backends/fs/posix/posix-fs.cpp @@ -24,85 +24,20 @@ #if defined(UNIX) -#include "backends/fs/abstract-fs.h" +#include "backends/fs/posix/posix-fs.h" +#include "backends/fs/stdiostream.h" +#include "common/algorithm.h" -#ifdef MACOSX -#include <sys/types.h> -#endif #include <sys/param.h> #include <sys/stat.h> #include <dirent.h> #include <stdio.h> -#include <unistd.h> -/** - * Implementation of the ScummVM file system API based on POSIX. - * - * Parts of this class are documented in the base interface class, AbstractFilesystemNode. - */ -class POSIXFilesystemNode : public AbstractFilesystemNode { -protected: - Common::String _displayName; - Common::String _path; - bool _isDirectory; - bool _isValid; - -public: - /** - * Creates a POSIXFilesystemNode with the root node as path. - */ - POSIXFilesystemNode(); - - /** - * Creates a POSIXFilesystemNode for a given path. - * - * @param path String with the path the new node should point to. - * @param verify true if the isValid and isDirectory flags should be verified during the construction. - */ - POSIXFilesystemNode(const Common::String &path, bool verify); - - virtual bool exists() const { return access(_path.c_str(), F_OK) == 0; } - virtual Common::String getDisplayName() const { return _displayName; } - virtual Common::String getName() const { return _displayName; } - virtual Common::String getPath() const { return _path; } - virtual bool isDirectory() const { return _isDirectory; } - virtual bool isReadable() const { return access(_path.c_str(), R_OK) == 0; } - virtual bool isWritable() const { return access(_path.c_str(), W_OK) == 0; } - - virtual AbstractFilesystemNode *getChild(const Common::String &n) const; - virtual bool getChildren(AbstractFSList &list, ListMode mode, bool hidden) const; - virtual AbstractFilesystemNode *getParent() const; - -private: - /** - * Tests and sets the _isValid and _isDirectory flags, using the stat() function. - */ - virtual void setFlags(); -}; - -/** - * Returns the last component of a given path. - * - * Examples: - * /foo/bar.txt would return /bar.txt - * /foo/bar/ would return /bar/ - * - * @param str String containing the path. - * @return Pointer to the first char of the last component inside str. - */ -const char *lastPathComponent(const Common::String &str) { - if(str.empty()) - return ""; - - const char *start = str.c_str(); - const char *cur = start + str.size() - 2; - - while (cur >= start && *cur != '/') { - --cur; - } +#ifdef __OS2__ +#define INCL_DOS +#include <os2.h> +#endif - return cur + 1; -} void POSIXFilesystemNode::setFlags() { struct stat st; @@ -111,15 +46,7 @@ void POSIXFilesystemNode::setFlags() { _isDirectory = _isValid ? S_ISDIR(st.st_mode) : false; } -POSIXFilesystemNode::POSIXFilesystemNode() { - // The root dir. - _path = "/"; - _displayName = _path; - _isValid = true; - _isDirectory = true; -} - -POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p, bool verify) { +POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p) { assert(p.size() > 0); // Expand "~/" to the value of the HOME env variable @@ -134,30 +61,85 @@ POSIXFilesystemNode::POSIXFilesystemNode(const Common::String &p, bool verify) { } else { _path = p; } - - _displayName = lastPathComponent(_path); - - if (verify) { - setFlags(); + +#ifdef __OS2__ + // On OS/2, 'X:/' is a root of drive X, so we should not remove that last + // slash. + if (!(_path.size() == 3 && _path.hasSuffix(":/"))) +#endif + // Normalize the path (that is, remove unneeded slashes etc.) + _path = Common::normalizePath(_path, '/'); + _displayName = Common::lastPathComponent(_path, '/'); + + // TODO: should we turn relative paths into absolute ones? + // Pro: Ensures the "getParent" works correctly even for relative dirs. + // Contra: The user may wish to use (and keep!) relative paths in his + // config file, and converting relative to absolute paths may hurt him... + // + // An alternative approach would be to change getParent() to work correctly + // if "_path" is the empty string. +#if 0 + if (!_path.hasPrefix("/")) { + char buf[MAXPATHLEN+1]; + getcwd(buf, MAXPATHLEN); + strcat(buf, "/"); + _path = buf + _path; } +#endif + // TODO: Should we enforce that the path is absolute at this point? + //assert(_path.hasPrefix("/")); + + setFlags(); } AbstractFilesystemNode *POSIXFilesystemNode::getChild(const Common::String &n) const { - // FIXME: Pretty lame implementation! We do no error checking to speak - // of, do not check if this is a special node, etc. + assert(!_path.empty()); assert(_isDirectory); + + // Make sure the string contains no slashes + assert(!n.contains('/')); + // We assume here that _path is already normalized (hence don't bother to call + // Common::normalizePath on the final path). Common::String newPath(_path); if (_path.lastChar() != '/') newPath += '/'; newPath += n; - return new POSIXFilesystemNode(newPath, true); + return makeNode(newPath); } bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const { assert(_isDirectory); +#ifdef __OS2__ + if (_path == "/") { + // Special case for the root dir: List all DOS drives + ULONG ulDrvNum; + ULONG ulDrvMap; + + DosQueryCurrentDisk(&ulDrvNum, &ulDrvMap); + + for (int i = 0; i < 26; i++) { + if (ulDrvMap & 1) { + char drive_root[] = "A:/"; + drive_root[0] += i; + + POSIXFilesystemNode *entry = new POSIXFilesystemNode(); + entry->_isDirectory = true; + entry->_isValid = true; + entry->_path = drive_root; + entry->_displayName = "[" + Common::String(drive_root, 2) + "]"; + myList.push_back(entry); + } + + ulDrvMap >>= 1; + } + + return true; + } +#endif + DIR *dirp = opendir(_path.c_str()); struct dirent *dp; @@ -175,12 +157,12 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo continue; } - Common::String newPath(_path); - if (newPath.lastChar() != '/') - newPath += '/'; - newPath += dp->d_name; - - POSIXFilesystemNode entry(newPath, false); + // Start with a clone of this node, with the correct path set + POSIXFilesystemNode entry(*this); + entry._displayName = dp->d_name; + if (_path.lastChar() != '/') + entry._path += '/'; + entry._path += entry._displayName; #if defined(SYSTEM_NOT_SUPPORTING_D_TYPE) /* TODO: d_type is not part of POSIX, so it might not be supported @@ -215,13 +197,10 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo continue; // Honor the chosen mode - if ((mode == FilesystemNode::kListFilesOnly && entry._isDirectory) || - (mode == FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) + if ((mode == Common::FilesystemNode::kListFilesOnly && entry._isDirectory) || + (mode == Common::FilesystemNode::kListDirectoriesOnly && !entry._isDirectory)) continue; - if (entry._isDirectory) - entry._path += "/"; - myList.push_back(new POSIXFilesystemNode(entry)); } closedir(dirp); @@ -231,12 +210,39 @@ bool POSIXFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo AbstractFilesystemNode *POSIXFilesystemNode::getParent() const { if (_path == "/") - return 0; + return 0; // The filesystem root has no parent + +#ifdef __OS2__ + if (_path.size() == 3 && _path.hasSuffix(":/")) + // This is a root directory of a drive + return makeNode("/"); // return a virtual root for a list of drives +#endif const char *start = _path.c_str(); - const char *end = lastPathComponent(_path); + const char *end = start + _path.size(); + + // Strip of the last component. We make use of the fact that at this + // point, _path is guaranteed to be normalized + while (end > start && *(end-1) != '/') + end--; + + if (end == start) { + // This only happens if we were called with a relative path, for which + // there simply is no parent. + // TODO: We could also resolve this by assuming that the parent is the + // current working directory, and returning a node referring to that. + return 0; + } + + return makeNode(Common::String(start, end)); +} + +Common::SeekableReadStream *POSIXFilesystemNode::openForReading() { + return StdioStream::makeFromPath(getPath().c_str(), false); +} - return new POSIXFilesystemNode(Common::String(start, end - start), true); +Common::WriteStream *POSIXFilesystemNode::openForWriting() { + return StdioStream::makeFromPath(getPath().c_str(), true); } #endif //#if defined(UNIX) |
