Coverage Report

Created: 2023-11-12 09:30

/proc/self/cwd/envoy/filesystem/filesystem.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
3
#include <bitset>
4
#include <cstdint>
5
#include <memory>
6
#include <string>
7
8
#include "envoy/api/io_error.h"
9
#include "envoy/common/platform.h"
10
#include "envoy/common/pure.h"
11
#include "envoy/common/time.h"
12
13
#include "absl/status/statusor.h"
14
#include "absl/strings/string_view.h"
15
#include "absl/types/optional.h"
16
17
namespace Envoy {
18
namespace Filesystem {
19
20
using FlagSet = std::bitset<5>;
21
22
enum class DestinationType { File, Stderr, Stdout, TmpFile };
23
24
enum class FileType { Regular, Directory, Other };
25
26
struct FileInfo {
27
  const std::string name_;
28
  // the size of the file in bytes, or `nullopt` if the size could not be determined
29
  //         (e.g. for directories, or windows symlinks.)
30
  const absl::optional<uint64_t> size_;
31
  // Note that if the file represented by name_ is a symlink, type_ will be the file type of the
32
  // target. For example, if name_ is a symlink to a directory, its file type will be Directory.
33
  // A broken symlink on posix will have `FileType::Regular`.
34
  const FileType file_type_;
35
  const absl::optional<SystemTime> time_created_;
36
  const absl::optional<SystemTime> time_last_accessed_;
37
  const absl::optional<SystemTime> time_last_modified_;
38
};
39
40
/**
41
 * Abstraction for a basic file on disk.
42
 */
43
class File {
44
public:
45
17.4k
  virtual ~File() = default;
46
47
  enum Operation {
48
    // Open a file for reading.
49
    Read,
50
    // Open a file for writing. The file will be truncated if neither Append nor
51
    // KeepExisting is set.
52
    Write,
53
    // Create the file if it does not already exist
54
    Create,
55
    // If writing, append to the file rather than writing to the beginning and
56
    // truncating after write.
57
    Append,
58
    // To open for write, without appending, and without truncating, add the
59
    // KeepExistingData flag. It is especially important to set this flag if
60
    // using pwrite, as the Windows implementation of truncation will interact
61
    // poorly with pwrite.
62
    KeepExistingData,
63
  };
64
65
  /**
66
   * Open the file with Flag
67
   * The file will be closed when this object is destructed
68
   *
69
   * @return bool whether the open succeeded
70
   */
71
  virtual Api::IoCallBoolResult open(FlagSet flags) PURE;
72
73
  /**
74
   * Write the buffer to the file. The file must be explicitly opened before writing.
75
   *
76
   * @return ssize_t number of bytes written, or -1 for failure
77
   */
78
  virtual Api::IoCallSizeResult write(absl::string_view buffer) PURE;
79
80
  /**
81
   * Get additional details about the file. May or may not require a file system operation.
82
   *
83
   * @return FileInfo the file info.
84
   */
85
  virtual Api::IoCallResult<FileInfo> info() PURE;
86
87
  /**
88
   * Close the file.
89
   *
90
   * @return bool whether the close succeeded
91
   */
92
  virtual Api::IoCallBoolResult close() PURE;
93
94
  /**
95
   * Read a chunk of data from the file to a buffer. The file must be explicitly opened
96
   * before reading.
97
   * @param buf The buffer to copy the data into.
98
   * @param count The maximum number of bytes to read.
99
   * @param offset The offset in the file at which to start reading.
100
   * @return ssize_t number of bytes read, or -1 for failure.
101
   */
102
  virtual Api::IoCallSizeResult pread(void* buf, uint64_t count, uint64_t offset) PURE;
103
104
  /**
105
   * Write a chunk of data from a buffer to the file. The file must be explicitly opened
106
   * before writing.
107
   * @param buf The buffer to read the data from.
108
   * @param count The maximum number of bytes to write.
109
   * @param offset The offset in the file at which to start writing.
110
   * @return ssize_t number of bytes written, or -1 for failure.
111
   */
112
  virtual Api::IoCallSizeResult pwrite(const void* buf, uint64_t count, uint64_t offset) PURE;
113
114
  /**
115
   * @return bool is the file open
116
   */
117
  virtual bool isOpen() const PURE;
118
119
  /**
120
   * @return string the file path
121
   */
122
  virtual std::string path() const PURE;
123
124
  /**
125
   * @return the type of the destination
126
   */
127
  virtual DestinationType destinationType() const PURE;
128
};
129
130
using FilePtr = std::unique_ptr<File>;
131
132
/**
133
 * Contains the result of splitting the file name and its parent directory from
134
 * a given file path.
135
 */
136
struct PathSplitResult {
137
  absl::string_view directory_;
138
  absl::string_view file_;
139
};
140
141
/**
142
 * Contains the file type and the path.
143
 */
144
struct FilePathAndType {
145
0
  bool operator==(const FilePathAndType& rhs) const {
146
0
    return file_type_ == rhs.file_type_ && path_ == rhs.path_;
147
0
  }
148
  FilePathAndType() = default;
149
  FilePathAndType(DestinationType file_type, absl::string_view path)
150
18.2k
      : file_type_(file_type), path_(path) {}
151
  DestinationType file_type_;
152
  std::string path_;
153
};
154
155
/**
156
 * Abstraction for some basic filesystem operations
157
 */
158
class Instance {
159
public:
160
27.3k
  virtual ~Instance() = default;
161
162
  /**
163
   *  @param file_info The path and the type of the File
164
   *  @return a FilePtr. The file is not opened.
165
   */
166
  virtual FilePtr createFile(const FilePathAndType& file_info) PURE;
167
168
  /**
169
   * @return bool whether a file exists on disk and can be opened for read.
170
   */
171
  virtual bool fileExists(const std::string& path) PURE;
172
173
  /**
174
   * @return FileInfo containing information about the file, or an error status.
175
   */
176
  virtual Api::IoCallResult<FileInfo> stat(absl::string_view path) PURE;
177
178
  /**
179
   * Attempts to create the given path, recursively if necessary.
180
   * @return bool true if one or more directories was created and the path exists,
181
   *         false if the path already existed, an error status if the path does
182
   *         not exist after the call.
183
   */
184
  virtual Api::IoCallBoolResult createPath(absl::string_view path) PURE;
185
186
  /**
187
   * @return bool whether a directory exists on disk and can be opened for read.
188
   */
189
  virtual bool directoryExists(const std::string& path) PURE;
190
191
  /**
192
   * @return ssize_t the size in bytes of the specified file, or -1 if the file size
193
   *                 cannot be determined for any reason, including without limitation
194
   *                 the non-existence of the file.
195
   */
196
  virtual ssize_t fileSize(const std::string& path) PURE;
197
198
  /**
199
   * @return full file content as a string or an error if the file can not be read.
200
   * Be aware, this is not most highly performing file reading method.
201
   */
202
  virtual absl::StatusOr<std::string> fileReadToEnd(const std::string& path) PURE;
203
204
  /**
205
   * @path file path to split
206
   * @return PathSplitResult containing the parent directory of the input path and the file name or
207
   * an error status.
208
   */
209
  virtual absl::StatusOr<PathSplitResult> splitPathFromFilename(absl::string_view path) PURE;
210
211
  /**
212
   * Determine if the path is on a list of paths Envoy will refuse to access. This
213
   * is a basic sanity check for users, denying some clearly bad paths. Paths
214
   * may still be problematic (e.g. indirectly leading to /dev/mem) even if this
215
   * returns false, it is up to the user to validate that supplied paths are
216
   * valid.
217
   * @param path some filesystem path.
218
   * @return is the path on the deny list?
219
   */
220
  virtual bool illegalPath(const std::string& path) PURE;
221
};
222
223
using InstancePtr = std::unique_ptr<Instance>;
224
225
struct DirectoryEntry {
226
  // name_ is the name of the file in the directory, not including the directory path itself
227
  // For example, if we have directory a/b containing file c, name_ will be c
228
  std::string name_;
229
230
  // Note that if the file represented by name_ is a symlink, type_ will be the file type of the
231
  // target. For example, if name_ is a symlink to a directory, its file type will be Directory.
232
  FileType type_;
233
234
  // The file size in bytes for regular files. nullopt for FileType::Directory and FileType::Other,
235
  // and, on Windows, also nullopt for symlinks, and on Linux nullopt for broken symlinks.
236
  absl::optional<uint64_t> size_bytes_;
237
238
15.7k
  bool operator==(const DirectoryEntry& rhs) const {
239
15.7k
    return name_ == rhs.name_ && type_ == rhs.type_ && size_bytes_ == rhs.size_bytes_;
240
15.7k
  }
241
};
242
243
class DirectoryIteratorImpl;
244
class DirectoryIterator {
245
public:
246
13.5k
  DirectoryIterator() : entry_({"", FileType::Other, absl::nullopt}) {}
247
13.5k
  virtual ~DirectoryIterator() = default;
248
249
28.5k
  const DirectoryEntry& operator*() const { return entry_; }
250
251
15.7k
  bool operator!=(const DirectoryIterator& rhs) const { return !(entry_ == *rhs); }
252
253
  virtual DirectoryIteratorImpl& operator++() PURE;
254
255
protected:
256
  DirectoryEntry entry_;
257
};
258
259
} // namespace Filesystem
260
} // namespace Envoy