From d3285646abba342212bb55e6521e0a229873ce09 Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Wed, 22 Jun 2022 20:54:06 -0230 Subject: [PATCH] getChildren now works correctly. --- src/emucore/FSNode.hxx | 20 +++--- src/unix/FSNodePOSIX.cxx | 131 +++++++++++---------------------------- src/unix/FSNodePOSIX.hxx | 8 +-- 3 files changed, 50 insertions(+), 109 deletions(-) diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index a84d64952..429603209 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -128,16 +128,16 @@ class FSNode bool exists() const; /** - * Return a list of child nodes of this and all sub-directories. If called on a node - * that does not represent a directory, false is returned. + * Return a list of child nodes of this and all sub-directories. If called + * on a node that does not represent a directory, false is returned. * * @return true if successful, false otherwise (e.g. when the directory * does not exist). */ bool getAllChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly, - const NameFilter& filter = [](const FSNode&) { return true; }, - bool includeParentDirectory = true, - const CancelCheck& isCancelled = []() { return false; }) const; + const NameFilter& filter = [](const FSNode&) { return true; }, + bool includeParentDirectory = true, + const CancelCheck& isCancelled = []() { return false; }) const; /** * Return a list of child nodes of this directory node. If called on a node @@ -147,10 +147,10 @@ class FSNode * does not exist). */ bool getChildren(FSList& fslist, ListMode mode = ListMode::DirectoriesOnly, - const NameFilter& filter = [](const FSNode&){ return true; }, - bool includeChildDirectories = false, - bool includeParentDirectory = true, - const CancelCheck& isCancelled = []() { return false; }) const; + const NameFilter& filter = [](const FSNode&){ return true; }, + bool includeChildDirectories = false, + bool includeParentDirectory = true, + const CancelCheck& isCancelled = []() { return false; }) const; /** * Set/get a string representation of the name of the file. This is can be @@ -452,7 +452,7 @@ class AbstractFSNode * * @return Size (in bytes) of the current node path. */ - virtual size_t getSize() const { return 0; } + virtual size_t getSize() const = 0; /** * Read data (binary format) into the given buffer. diff --git a/src/unix/FSNodePOSIX.cxx b/src/unix/FSNodePOSIX.cxx index fbeb7198a..bf8ad7076 100644 --- a/src/unix/FSNodePOSIX.cxx +++ b/src/unix/FSNodePOSIX.cxx @@ -64,7 +64,6 @@ FSNodePOSIX::FSNodePOSIX(const string& path, bool verify) // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void FSNodePOSIX::setFlags() { -#if 1 // cerr << "_fspath: " << _fspath << endl; std::error_code ec; const auto s = fs::status(_fspath, ec); @@ -72,7 +71,6 @@ void FSNodePOSIX::setFlags() { const auto p = s.permissions(); - _isValid = true; _isFile = fs::is_regular_file(s); _isDirectory = fs::is_directory(s); _isReadable = (p & (fs::perms::owner_read | @@ -81,32 +79,20 @@ void FSNodePOSIX::setFlags() _isWriteable = (p & (fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write)) != fs::perms::none; -// cerr << "_isValid: " << _isValid << endl -// << "_isFile: " << _isFile << endl + _size = _isFile ? fs::file_size(_fspath) : 0; + +// cerr << "_isFile: " << _isFile << endl // << "_isDirectory: " << _isDirectory << endl // << "_isReadable: " << _isReadable << endl // << "_isWriteable: " << _isWriteable << endl +// << "_size: " << _size << endl // << endl; } else - _isValid = _isFile = _isDirectory = _isReadable = _isWriteable = false; - -#else - struct stat st; - - _isValid = (0 == stat(_path.c_str(), &st)); - if(_isValid) { - _isDirectory = S_ISDIR(st.st_mode); - _isFile = S_ISREG(st.st_mode); - - // Add a trailing slash, if necessary - if (_isDirectory && _path.length() > 0 && _path[_path.length()-1] != '/') - _path += '/'; + _isFile = _isDirectory = _isReadable = _isWriteable = false; + _size = 0; } - else - _isDirectory = _isFile = false; -#endif } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -140,93 +126,48 @@ bool FSNodePOSIX::hasParent() const // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - bool FSNodePOSIX::getChildren(AbstractFSList& myList, ListMode mode) const { -cerr << "getChildren: " << _path << endl; - assert(_isDirectory); - - DIR* dirp = opendir(_path.c_str()); - if (dirp == nullptr) - return false; - - // Loop over dir entries using readdir - struct dirent* dp = nullptr; - while ((dp = readdir(dirp)) != nullptr) +// cerr << "getChildren: " << _path << endl; + std::error_code ec; + for (const auto& entry: fs::directory_iterator{_fspath, + fs::directory_options::follow_directory_symlink | + fs::directory_options::skip_permission_denied, + ec + }) { - // Ignore all hidden files - if (dp->d_name[0] == '.') - continue; + const auto& path = entry.path(); - string newPath(_path); - if (newPath.length() > 0 && newPath[newPath.length()-1] != '/') - newPath += '/'; - newPath += dp->d_name; - - FSNodePOSIX entry(newPath, false); - -#if defined(SYSTEM_NOT_SUPPORTING_D_TYPE) - /* TODO: d_type is not part of POSIX, so it might not be supported - * on some of our targets. For those systems where it isn't supported, - * add this #elif case, which tries to use stat() instead. - * - * The d_type method is used to avoid costly recurrent stat() calls in big - * directories. - */ - entry.setFlags(); -#else - if (dp->d_type == DT_UNKNOWN) - { - // Fall back to stat() - entry.setFlags(); - } - else - { - if (dp->d_type == DT_LNK) - { - struct stat st; - if (stat(entry._path.c_str(), &st) == 0) - { - entry._isDirectory = S_ISDIR(st.st_mode); - entry._isFile = S_ISREG(st.st_mode); - } - else - entry._isDirectory = entry._isFile = false; - } - else - { - entry._isDirectory = (dp->d_type == DT_DIR); - entry._isFile = (dp->d_type == DT_REG); - } - - if (entry._isDirectory) - entry._path += "/"; - - entry._isValid = true; - } -#endif - - // Skip files that are invalid for some reason (e.g. because we couldn't - // properly stat them). - if (!entry._isValid) + // Ignore files with errors, or any that start with '.' + if (ec || path.filename().string()[0] == '.') continue; // Honor the chosen mode - if ((mode == FSNode::ListMode::FilesOnly && !entry._isFile) || - (mode == FSNode::ListMode::DirectoriesOnly && !entry._isDirectory)) + const bool isFile = entry.is_regular_file(), + isDir = entry.is_directory(); + if ((mode == FSNode::ListMode::FilesOnly && !isFile) || + (mode == FSNode::ListMode::DirectoriesOnly && !isDir)) continue; - myList.emplace_back(make_shared(entry)); + // Only create the object and add it to the list when absolutely + // necessary + FSNodePOSIX node(path.string(), false); + node._isFile = isFile; + node._isDirectory = isDir; + node._size = isFile ? entry.file_size() : 0; + + const auto p = entry.status().permissions(); + node._isReadable = (p & (fs::perms::owner_read | + fs::perms::group_read | + fs::perms::others_read)) != fs::perms::none; + node._isWriteable = (p & (fs::perms::owner_write | + fs::perms::group_write | + fs::perms::others_write)) != fs::perms::none; + + myList.emplace_back(make_shared(node)); } - closedir(dirp); return true; } -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t FSNodePOSIX::getSize() const -{ - struct stat st; - return (stat(_path.c_str(), &st) == 0) ? st.st_size : 0; -} - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - size_t FSNodePOSIX::read(ByteBuffer& buffer, size_t size) const { diff --git a/src/unix/FSNodePOSIX.hxx b/src/unix/FSNodePOSIX.hxx index b10d6c0aa..8fb6f8265 100644 --- a/src/unix/FSNodePOSIX.hxx +++ b/src/unix/FSNodePOSIX.hxx @@ -75,7 +75,7 @@ class FSNodePOSIX : public AbstractFSNode bool makeDir() override; bool rename(const string& newfile) override; - size_t getSize() const override; + size_t getSize() const override { return _size; } size_t read(ByteBuffer& buffer, size_t size) const override; size_t read(stringstream& buffer) const override; size_t write(const ByteBuffer& buffer, size_t size) const override; @@ -87,13 +87,13 @@ class FSNodePOSIX : public AbstractFSNode protected: fs::path _fspath; string _path, _displayName; - bool _isValid{false}, _isFile{false}, _isDirectory{false}, + bool _isFile{false}, _isDirectory{false}, _isReadable{false}, _isWriteable{false}; + size_t _size{0}; private: /** - * Tests and sets the _isValid and _isDirectory/_isFile flags, - * using the stat() function. + * Tests and sets the various flags for a file/directory. */ void setFlags(); };