/src/solidity/libsolidity/interface/FileReader.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | This file is part of solidity. |
3 | | |
4 | | solidity is free software: you can redistribute it and/or modify |
5 | | it under the terms of the GNU General Public License as published by |
6 | | the Free Software Foundation, either version 3 of the License, or |
7 | | (at your option) any later version. |
8 | | |
9 | | solidity is distributed in the hope that it will be useful, |
10 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | GNU General Public License for more details. |
13 | | |
14 | | You should have received a copy of the GNU General Public License |
15 | | along with solidity. If not, see <http://www.gnu.org/licenses/>. |
16 | | */ |
17 | | // SPDX-License-Identifier: GPL-3.0 |
18 | | #pragma once |
19 | | |
20 | | #include <libsolidity/interface/ImportRemapper.h> |
21 | | #include <libsolidity/interface/ReadFile.h> |
22 | | |
23 | | #include <boost/filesystem.hpp> |
24 | | |
25 | | #include <map> |
26 | | #include <set> |
27 | | |
28 | | namespace solidity::frontend |
29 | | { |
30 | | |
31 | | /// FileReader - used for progressively loading source code. |
32 | | /// |
33 | | /// It is used in solc to load files from CLI parameters, stdin, or from JSON and |
34 | | /// also used in the solc language server where solc is a long running process. |
35 | | class FileReader |
36 | | { |
37 | | public: |
38 | | using StringMap = std::map<SourceUnitName, SourceCode>; |
39 | | using PathMap = std::map<SourceUnitName, boost::filesystem::path>; |
40 | | using FileSystemPathSet = std::set<boost::filesystem::path>; |
41 | | |
42 | | enum SymlinkResolution { |
43 | | Disabled, ///< Do not resolve symbolic links in the path. |
44 | | Enabled, ///< Follow symbolic links. The path should contain no symlinks. |
45 | | }; |
46 | | |
47 | | /// Constructs a FileReader with a base path and sets of include paths and allowed directories |
48 | | /// that will be used when requesting files from this file reader instance. |
49 | | explicit FileReader( |
50 | | boost::filesystem::path _basePath = {}, |
51 | | std::vector<boost::filesystem::path> const& _includePaths = {}, |
52 | | FileSystemPathSet _allowedDirectories = {} |
53 | | ); |
54 | | |
55 | | void setBasePath(boost::filesystem::path const& _path); |
56 | 0 | boost::filesystem::path const& basePath() const noexcept { return m_basePath; } |
57 | | |
58 | | void addIncludePath(boost::filesystem::path const& _path); |
59 | 0 | std::vector<boost::filesystem::path> const& includePaths() const noexcept { return m_includePaths; } |
60 | | |
61 | | void allowDirectory(boost::filesystem::path _path); |
62 | 0 | FileSystemPathSet const& allowedDirectories() const noexcept { return m_allowedDirectories; } |
63 | | |
64 | | /// @returns all sources by their internal source unit names. |
65 | 0 | StringMap const& sourceUnits() const noexcept { return m_sourceCodes; } |
66 | | |
67 | | /// Resets all sources to the given map of source unit name to source codes. |
68 | | /// Does not enforce @a allowedDirectories(). |
69 | | void setSourceUnits(StringMap _sources); |
70 | | |
71 | | /// Adds the source code under a source unit name created by normalizing the file path |
72 | | /// or changes an existing source. |
73 | | /// Does not enforce @a allowedDirectories(). |
74 | | void addOrUpdateFile(boost::filesystem::path const& _path, SourceCode _source); |
75 | | |
76 | | /// Adds the source code under the source unit name of @a <stdin>. |
77 | | /// Does not enforce @a allowedDirectories(). |
78 | | void setStdin(SourceCode _source); |
79 | | |
80 | | /// Receives a @p _sourceUnitName that refers to a source unit in compiler's virtual filesystem |
81 | | /// and attempts to interpret it as a path and read the corresponding file from disk. |
82 | | /// The read will only succeed if the canonical path of the file is within one of the @a allowedDirectories(). |
83 | | /// @param _kind must be equal to "source". Other values are not supported. |
84 | | /// @return Content of the loaded file or an error message. If the operation succeeds, a copy of |
85 | | /// the content is retained in @a sourceUnits() under the key of @a _sourceUnitName. If the key |
86 | | /// already exists, previous content is discarded. |
87 | | frontend::ReadCallback::Result readFile(std::string const& _kind, std::string const& _sourceUnitName); |
88 | | |
89 | | frontend::ReadCallback::Callback reader() |
90 | 0 | { |
91 | 0 | return [this](std::string const& _kind, std::string const& _path) { return readFile(_kind, _path); }; |
92 | 0 | } |
93 | | |
94 | | /// Creates a source unit name by normalizing a path given on the command line and, if possible, |
95 | | /// making it relative to base path or one of the include directories. |
96 | | std::string cliPathToSourceUnitName(boost::filesystem::path const& _cliPath) const; |
97 | | |
98 | | /// Checks if a set contains any paths that lead to different files but would receive identical |
99 | | /// source unit names. Files are considered the same if their paths are exactly the same after |
100 | | /// normalization (without following symlinks). |
101 | | /// @returns a map containing all the conflicting source unit names and the paths that would |
102 | | /// receive them. The returned paths are normalized. |
103 | | std::map<std::string, FileSystemPathSet> detectSourceUnitNameCollisions(FileSystemPathSet const& _cliPaths) const; |
104 | | |
105 | | /// Normalizes a filesystem path to make it include all components up to the filesystem root, |
106 | | /// remove small, inconsequential differences that do not affect the meaning and make it look |
107 | | /// the same on all platforms (if possible). |
108 | | /// The resulting path uses forward slashes as path separators, has no redundant separators, |
109 | | /// has no redundant . or .. segments and has no root name if removing it does not change the meaning. |
110 | | /// The path does not have to actually exist. |
111 | | /// @param _path Path to normalize. |
112 | | /// @param _symlinkResolution If @a Disabled, any symlinks present in @a _path are preserved. |
113 | | static boost::filesystem::path normalizeCLIPathForVFS( |
114 | | boost::filesystem::path const& _path, |
115 | | SymlinkResolution _symlinkResolution = SymlinkResolution::Disabled |
116 | | ); |
117 | | |
118 | | /// Normalizes a root path by excluding, in some cases, its root name. |
119 | | /// The function is used for better portability, and intended to omit root name |
120 | | /// if the path can be used without it. |
121 | | /// @param _path Path to normalize the root path. |
122 | | /// @param _workDir Current working directory path, must be absolute. |
123 | | /// @returns a normalized root path. |
124 | | static boost::filesystem::path normalizeCLIRootPathForVFS( |
125 | | boost::filesystem::path const& _path, |
126 | | boost::filesystem::path const& _workDir = boost::filesystem::current_path() |
127 | | ); |
128 | | |
129 | | /// @returns true if all the path components of @a _prefix are present at the beginning of @a _path. |
130 | | /// Both paths must be absolute (or have slash as root) and normalized (no . or .. segments, no |
131 | | /// multiple consecutive slashes). |
132 | | /// Paths are treated as case-sensitive. Does not require the path to actually exist in the |
133 | | /// filesystem and does not follow symlinks. Only considers whole segments, e.g. /abc/d is not |
134 | | /// considered a prefix of /abc/def. Both paths must be non-empty. |
135 | | /// Ignores the trailing slash, i.e. /a/b/c.sol/ is treated as a valid prefix of /a/b/c.sol. |
136 | | static bool isPathPrefix(boost::filesystem::path const& _prefix, boost::filesystem::path const& _path); |
137 | | |
138 | | /// If @a _prefix is actually a prefix of @p _path, removes it from @a _path to make it relative. |
139 | | /// @returns The path without the prefix or unchanged path if there is not prefix. |
140 | | /// If @a _path and @_prefix are identical, the result is '.'. |
141 | | static boost::filesystem::path stripPrefixIfPresent(boost::filesystem::path const& _prefix, boost::filesystem::path const& _path); |
142 | | |
143 | | /// @returns true if the specified path is an UNC path. |
144 | | /// UNC paths start with // followed by a name (on Windows they can also start with \\). |
145 | | /// They are used for network shares on Windows. On UNIX systems they do not have the same |
146 | | /// functionality but usually they are still recognized and treated in a special way. |
147 | | static bool isUNCPath(boost::filesystem::path const& _path); |
148 | | |
149 | | private: |
150 | | /// If @a _path starts with a number of .. segments, returns a path consisting only of those |
151 | | /// segments (root name is not included). Otherwise returns an empty path. @a _path must be |
152 | | /// absolute (or have slash as root). |
153 | | static boost::filesystem::path absoluteDotDotPrefix(boost::filesystem::path const& _path); |
154 | | |
155 | | /// @returns true if the path contains any .. segments. |
156 | | static bool hasDotDotSegments(boost::filesystem::path const& _path); |
157 | | |
158 | | /// Base path, used for resolving relative paths in imports. |
159 | | boost::filesystem::path m_basePath; |
160 | | |
161 | | /// Additional directories used for resolving relative paths in imports. |
162 | | std::vector<boost::filesystem::path> m_includePaths; |
163 | | |
164 | | /// list of allowed directories to read files from |
165 | | FileSystemPathSet m_allowedDirectories; |
166 | | |
167 | | /// map of input files to source code strings |
168 | | StringMap m_sourceCodes; |
169 | | }; |
170 | | |
171 | | } |