/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity 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 GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ // SPDX-License-Identifier: GPL-3.0 #include #include #include #include #include using solidity::frontend::ReadCallback; using solidity::langutil::InternalCompilerError; using solidity::util::errinfo_comment; using solidity::util::readFileAsString; using std::string; namespace solidity::frontend { void FileReader::setSource(boost::filesystem::path const& _path, SourceCode _source) { m_sourceCodes[_path.generic_string()] = std::move(_source); } void FileReader::setSources(StringMap _sources) { m_sourceCodes = std::move(_sources); } ReadCallback::Result FileReader::readFile(string const& _kind, string const& _sourceUnitName) { try { if (_kind != ReadCallback::kindString(ReadCallback::Kind::ReadFile)) BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment( "ReadFile callback used as callback kind " + _kind )); string strippedSourceUnitName = _sourceUnitName; if (strippedSourceUnitName.find("file://") == 0) strippedSourceUnitName.erase(0, 7); auto canonicalPath = boost::filesystem::weakly_canonical(m_basePath / strippedSourceUnitName); bool isAllowed = false; for (auto const& allowedDir: m_allowedDirectories) { // If dir is a prefix of boostPath, we are fine. if ( std::distance(allowedDir.begin(), allowedDir.end()) <= std::distance(canonicalPath.begin(), canonicalPath.end()) && std::equal(allowedDir.begin(), allowedDir.end(), canonicalPath.begin()) ) { isAllowed = true; break; } } if (!isAllowed) return ReadCallback::Result{false, "File outside of allowed directories."}; if (!boost::filesystem::exists(canonicalPath)) return ReadCallback::Result{false, "File not found."}; if (!boost::filesystem::is_regular_file(canonicalPath)) return ReadCallback::Result{false, "Not a valid file."}; // NOTE: we ignore the FileNotFound exception as we manually check above auto contents = readFileAsString(canonicalPath.string()); m_sourceCodes[_sourceUnitName] = contents; return ReadCallback::Result{true, contents}; } catch (util::Exception const& _exception) { return ReadCallback::Result{false, "Exception in read callback: " + boost::diagnostic_information(_exception)}; } catch (...) { return ReadCallback::Result{false, "Unknown exception in read callback."}; } } }