#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2021 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License // If the library is compiled as a DLL, this ensures symbols are exported #define NUCLEX_STORAGE_SOURCE 1 #include "LinuxDirectoryContainer.h" #if defined(NUCLEX_STORAGE_LINUX) #include "Nuclex/Storage/FileSystem/Path.h" //#include "PosixFileApi.h" // Include Posix API everywhere but Windows #include "LinuxFileApi.h" #include #include // for std::runtime_error #include // also std::runtime_error on non-confirming compilers (MSVC) namespace { // ------------------------------------------------------------------------------------------- // /// Checks if the specified name indicates the current or parent directory /// Name that will be checked /// True if the name indicates the current or parent directory /// /// Name must be at least 3 characters long. /// bool isCurrentOrParentDirectoryName(const char *name) { return ( (name[0] == '.') && ( (name[1] == 0) || ( (name[1] == '.') && (name[2] == 0) ) ) ); } // ------------------------------------------------------------------------------------------- // /// Enumerates the contents of a directory /// Absolute path of the directory whose contents will be enumerated /// Filenames to look for /// /// Set to true to enumerate subdirectories rather than files below the specified path /// /// /// The absolute paths of all files or subdirectories under the specified path /// std::vector enumerateDirectoryContents( const std::string &path, const std::string &wildcard, bool subDirectoriesInsteadOfFiles ) { using Nuclex::Storage::FileSystem::Linux::LinuxFileApi; std::vector result; DIR *directoryHandle = LinuxFileApi::OpenDirectory(path); { Nuclex::Storage::FileSystem::Linux::DirectoryScope directoryScope(directoryHandle); for(;;) { struct ::dirent *directoryEntry = LinuxFileApi::ReadDirectory(directoryHandle); if(directoryEntry == nullptr) { break; // returning null indicates the end of the enumeration was reached } // Check if this is the current or parent directory reference. // d_name is a fixed-size char array, we can safely assume it will always // hold at least the 3 characters we're touching. if(isCurrentOrParentDirectoryName(directoryEntry->d_name)) { continue; } // The filename also needs to match the wildcard const bool caseSensitive = true; bool matchesMask = Nuclex::Support::Text::StringMatcher::FitsWildcard( directoryEntry->d_name, wildcard, caseSensitive ); if(!matchesMask) { continue; } // The readdir() function will only return directory/file names, so join // these to our own absolute path to make them absolute std::string filename = directoryEntry->d_name; std::string itemPath = Nuclex::Storage::FileSystem::Path::Join(path, filename); // Only add entries to the results that match the requested type ::mode_t fileMode = LinuxFileApi::StatMode(itemPath); if(S_ISDIR(fileMode) == subDirectoriesInsteadOfFiles) { #if defined(NUCLEX_STORAGE_ENUMERATION_RETURNS_FULL_PATHS) result.push_back(std::move(itemPath)); #else result.push_back(std::move(filename)); #endif } } } return result; } // ------------------------------------------------------------------------------------------- // /// Extracts the name of a directory from its absolute path /// /// Absolute path to a directory whose name will be extracted /// /// The name of the directory at the specified absolute path std::string getDirectoryName(const std::string &absolutePath) { std::string::size_type pathLength = absolutePath.length(); if(pathLength == 0) { #if defined(NUCLEX_STORAGE_WIN32) return std::string(u8"C:\\"); // TODO: Look for CWD or system drive? #else return std::string(u8"/"); #endif } #if defined(NUCLEX_STORAGE_WIN32) bool endsWithDirectorySeparator = ( (absolutePath[pathLength] == '/') || (absolutePath[pathLength] == '\\') ); #else bool endsWithDirectorySeparator = (absolutePath[pathLength] == '/'); #endif std::string name; if(endsWithDirectorySeparator) { name = Nuclex::Storage::FileSystem::Path::GetFilename( absolutePath.substr(0, pathLength - 1) ); } else { name = Nuclex::Storage::FileSystem::Path::GetFilename(absolutePath); } if(name.empty()) { #if defined(NUCLEX_STORAGE_WIN32) return std::string(u8"C:\\"); // TODO: Look for CWD or system drive? #else return std::string(u8"/"); #endif } return name; } // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Storage { namespace FileSystem { namespace Linux { // ------------------------------------------------------------------------------------------- // LinuxDirectoryContainer::LinuxDirectoryContainer(const std::string &absolutePath) : absolutePath(absolutePath), name(getDirectoryName(absolutePath)) {} // ------------------------------------------------------------------------------------------- // std::vector LinuxDirectoryContainer::EnumerateContainers( const std::string &wildcard /* = u8"*" */ ) const { const bool subDirectoriesInsteadOfFiles = true; return enumerateDirectoryContents( this->absolutePath, wildcard, subDirectoriesInsteadOfFiles ); } // ------------------------------------------------------------------------------------------- // std::vector LinuxDirectoryContainer::EnumerateFiles( const std::string &wildcard /* = u8"*" */ ) const { const bool subDirectoriesInsteadOfFiles = false; return enumerateDirectoryContents( this->absolutePath, wildcard, subDirectoriesInsteadOfFiles ); } // ------------------------------------------------------------------------------------------- // std::shared_ptr LinuxDirectoryContainer::AccessContainer(const std::string &name) { if(name.find('/') != std::string::npos) { throw std::runtime_error(u8"Invalid subdirectory name"); } return std::make_shared( Path::Join(this->absolutePath, name) ); } // ------------------------------------------------------------------------------------------- // std::shared_ptr LinuxDirectoryContainer::AccessContainer( const std::string &name ) const { if(name.find('/') != std::string::npos) { throw std::runtime_error(u8"Invalid subdirectory name"); } return std::make_shared( Path::Join(this->absolutePath, name) ); } // ------------------------------------------------------------------------------------------- // }}}} // namespace Nuclex::Storage::FileSystem::Linux #endif // defined(NUCLEX_STORAGE_LINUX)