#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 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 "LinuxContainer.h" #if defined(NUCLEX_STORAGE_LINUX) #include "LinuxFile.h" #include "LinuxPathHelper.h" #include "LinuxFileApi.h" #include "Nuclex/Storage/FileSystem/ContainerFileCodec.h" #include "Nuclex/Storage/Helpers/StringHelper.h" #include #include namespace { // ------------------------------------------------------------------------------------------- // /// Automatically closes a directory handle when the scope is left class DirectoryHandleScope { /// Initializes a new directory handle scope /// Directory handle that will be closed public: DirectoryHandleScope(DIR *directoryHandle) : directoryHandle(directoryHandle) {} /// Closes the directory handle public: ~DirectoryHandleScope() { Nuclex::Storage::FileSystem::LinuxFileApi::CloseDirectory(this->directoryHandle); } /// Directory handle the scope will close private: DIR *directoryHandle; }; // ------------------------------------------------------------------------------------------- // /// Enumerates all directories in a specified path /// Directory whose contents will be enumerated /// Wildcard the returned files and directory need to match /// Whether to also enumerate directories /// The absolute paths of all files and directories under the path std::pair< std::vector, std::vector > enumerate( const std::string &path, const std::string &wildcard, bool includeDirectories = true ) { using namespace Nuclex::Storage; using namespace Nuclex::Storage::Helpers; using namespace Nuclex::Storage::FileSystem; std::vector directories; std::vector files; DIR *directoryHandle = LinuxFileApi::OpenDirectory(path); DirectoryHandleScope directoryHandleScope(directoryHandle); { struct dirent directoryEntry; while(LinuxFileApi::ReadDirectory(directoryHandle, directoryEntry)) { if(directoryEntry.d_name[0] == '.') { continue; } std::string filename(directoryEntry.d_name); if(StringHelper::MatchesWildcard(filename, wildcard)) { std::string filePath = LinuxPathHelper::MakeAbsolute(path, filename); mode_t fileMode = LinuxFileApi::StatMode(filePath); if(!S_ISDIR(fileMode)) { files.push_back(filePath); } else if(includeDirectories) { directories.push_back(filePath); } } } } return std::make_pair(files, directories); } // ------------------------------------------------------------------------------------------- // } // anonymous namespace namespace Nuclex { namespace Storage { namespace FileSystem { // ------------------------------------------------------------------------------------------- // LinuxContainer::LinuxContainer( const std::shared_ptr &codecs, const std::string &absolutePath ) : Container(codecs), path(absolutePath), name(LinuxPathHelper::GetLastPathElement(absolutePath)) {} // ------------------------------------------------------------------------------------------- // LinuxContainer::~LinuxContainer() {} // ------------------------------------------------------------------------------------------- // std::vector LinuxContainer::GetContainers( const std::string &wildcard /* = std::string() */ ) const { std::pair contents = enumerate(this->path, wildcard); std::vector containers(contents.second.size()); for(std::size_t index = 0; index < contents.second.size(); ++index) { containers[index] = std::shared_ptr( new LinuxContainer(this->Codecs, contents.second[index]) ); } for(std::size_t index = 0; index < contents.first.size(); ++index) { std::shared_ptr file(new LinuxFile(contents.first[index])); std::shared_ptr container; bool wasOpened = this->Codecs->TryOpenAsContainer(this->Codecs, file, container); if(wasOpened) { containers.push_back(container); } } return containers; } // ------------------------------------------------------------------------------------------- // std::vector LinuxContainer::GetContainers( const std::string &wildcard /* = std::string() */ ) { std::pair contents = enumerate(this->path, wildcard); std::vector containers(contents.second.size()); for(std::size_t index = 0; index < contents.second.size(); ++index) { containers[index] = std::shared_ptr( new LinuxContainer(this->Codecs, contents.second[index]) ); } for(std::size_t index = 0; index < contents.first.size(); ++index) { std::shared_ptr file(new LinuxFile(contents.first[index])); std::shared_ptr container; bool wasOpened = this->Codecs->TryOpenAsContainer(this->Codecs, file, container); if(wasOpened) { containers.push_back(container); } } return containers; } // ------------------------------------------------------------------------------------------- // LinuxContainer::ConstContainerPointer LinuxContainer::GetContainer( const std::string &name ) const { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode == 0) { throw std::runtime_error("Directory does not exist"); } if(S_ISDIR(fileMode)) { return std::shared_ptr(new LinuxContainer(this->Codecs, containerPath)); } else { std::shared_ptr file(new LinuxFile(containerPath)); std::shared_ptr container; bool wasOpened = this->Codecs->TryOpenAsContainer(this->Codecs, file, container); if(wasOpened) { return container; } else { throw std::runtime_error("Could not open this file as a container"); } } } // ------------------------------------------------------------------------------------------- // LinuxContainer::ContainerPointer LinuxContainer::GetContainer(const std::string &name) { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode == 0) { throw std::runtime_error("Directory does not exist"); } if(S_ISDIR(fileMode)) { return std::shared_ptr(new LinuxContainer(this->Codecs, containerPath)); } else { std::shared_ptr file(new LinuxFile(containerPath)); std::shared_ptr container; bool wasOpened = this->Codecs->TryOpenAsContainer(this->Codecs, file, container); if(wasOpened) { return container; } else { throw std::runtime_error("Could not open this file as a container"); } } } // ------------------------------------------------------------------------------------------- // bool LinuxContainer::HasContainer(const std::string &name) const { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode == 0) { return false; } else if(S_ISDIR(fileMode)) { return true; } else { std::shared_ptr file(new LinuxFile(containerPath)); return this->Codecs->CanOpenAsContainer(file); } } // ------------------------------------------------------------------------------------------- // LinuxContainer::ContainerPointer LinuxContainer::CreateContainer( const std::string &name ) { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode != 0) { throw std::runtime_error("Directory or file with same name already exists"); } LinuxFileApi::MakeDirectory(containerPath); // TODO: Allow container file codecs to create containers return std::shared_ptr(new LinuxContainer(this->Codecs, containerPath)); } // ------------------------------------------------------------------------------------------- // void LinuxContainer::DeleteContainer(const std::string &name) { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode == 0) { throw std::runtime_error("Directory does not exist"); } if(!S_ISDIR(fileMode)) { bool canOpenAsContainer; { std::shared_ptr file(new LinuxFile(containerPath)); canOpenAsContainer = this->Codecs->CanOpenAsContainer(file); } if(canOpenAsContainer) { LinuxFileApi::RemoveFile(containerPath); } else { throw std::runtime_error("Could not delete this file as a container"); } } LinuxFileApi::RemoveDirectory(containerPath); } // ------------------------------------------------------------------------------------------- // std::vector LinuxContainer::GetFiles( const std::string &wildcard /* = std::string() */ ) const { std::pair contents = enumerate(this->path, wildcard, false); std::vector files(contents.first.size()); for(std::size_t index = 0; index < contents.first.size(); ++index) { files[index] = std::shared_ptr(new LinuxFile(contents.first[index])); } return files; } // ------------------------------------------------------------------------------------------- // std::vector LinuxContainer::GetFiles( const std::string &wildcard /* = std::string() */ ) { std::pair contents = enumerate(this->path, wildcard, false); std::vector files(contents.first.size()); for(std::size_t index = 0; index < contents.first.size(); ++index) { files[index] = std::shared_ptr(new LinuxFile(contents.first[index])); } return files; } // ------------------------------------------------------------------------------------------- // LinuxContainer::ConstFilePointer LinuxContainer::GetFile(const std::string &name) const { std::string filePath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(filePath); if(fileMode == 0) { throw std::runtime_error("File does not exist"); } if(S_ISDIR(fileMode)) { throw std::runtime_error("Could not open directory as a file"); } return std::shared_ptr(new LinuxFile(filePath)); } // ------------------------------------------------------------------------------------------- // LinuxContainer::FilePointer LinuxContainer::GetFile(const std::string &name) { std::string filePath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(filePath); if(fileMode == 0) { throw std::runtime_error("File does not exist"); } if(S_ISDIR(fileMode)) { throw std::runtime_error("Could not open directory as a file"); } return std::shared_ptr(new LinuxFile(filePath)); } // ------------------------------------------------------------------------------------------- // bool LinuxContainer::HasFile(const std::string &name) const { std::string containerPath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(containerPath); if(fileMode == 0) { return false; } else if(S_ISDIR(fileMode)) { return false; } else { return true; } } // ------------------------------------------------------------------------------------------- // LinuxContainer::FilePointer LinuxContainer::CreateFile(const std::string &name) { std::string filePath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(filePath); if(fileMode != 0) { throw std::runtime_error("File or directory with the same name already exists"); } // Make sure the file is created right away std::shared_ptr newFile(new LinuxFile(filePath)); newFile->WriteAt(0, nullptr, 0); return newFile; } // ------------------------------------------------------------------------------------------- // void LinuxContainer::DeleteFile(const std::string &name) { std::string filePath = LinuxPathHelper::MakeAbsolute(this->path, name); mode_t fileMode = LinuxFileApi::StatMode(filePath); if(fileMode == 0) { throw std::runtime_error("File does not exist"); } if(S_ISDIR(fileMode)) { throw std::runtime_error("Could not delete directory as a file"); } LinuxFileApi::RemoveFile(filePath); } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Storage::FileSystem #endif // defined(NUCLEX_STORAGE_LINUX)