Coverage Report

Created: 2025-08-25 06:58

/src/WasmEdge/include/host/wasi/vinode.h
Line
Count
Source (jump to first uncovered line)
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: 2019-2024 Second State INC
3
4
#pragma once
5
6
#include "common/filesystem.h"
7
#include "host/wasi/error.h"
8
#include "host/wasi/inode.h"
9
#include "host/wasi/vfs.h"
10
11
#include <cstdint>
12
#include <functional>
13
#include <memory>
14
#include <string>
15
#include <string_view>
16
#include <utility>
17
#include <vector>
18
19
namespace WasmEdge {
20
namespace Host {
21
namespace WASI {
22
23
class VPoller;
24
class VINode : public std::enable_shared_from_this<VINode> {
25
public:
26
  VINode(const VINode &) = delete;
27
  VINode &operator=(const VINode &) = delete;
28
  VINode(VINode &&) = default;
29
  VINode &operator=(VINode &&) = default;
30
31
  /// Create a VINode with a parent.
32
  ///
33
  /// @param[in] Node System INode.
34
  VINode(INode Node);
35
36
  /// Create a orphan VINode.
37
  ///
38
  /// @param[in] Node System INode.
39
  /// @param[in] FRB The desired rights of the VINode.
40
  /// @param[in] FRI The desired rights of the VINode.
41
  VINode(INode Node, __wasi_rights_t FRB, __wasi_rights_t FRI,
42
         std::string N = {});
43
44
  /// Check path is valid.
45
0
  static bool isPathValid(std::string_view Path) noexcept {
46
0
    return Path.find('\0') == std::string_view::npos;
47
0
  }
48
49
  static std::shared_ptr<VINode> stdIn(__wasi_rights_t FRB,
50
                                       __wasi_rights_t FRI);
51
  static std::shared_ptr<VINode> stdOut(__wasi_rights_t FRB,
52
                                        __wasi_rights_t FRI);
53
  static std::shared_ptr<VINode> stdErr(__wasi_rights_t FRB,
54
                                        __wasi_rights_t FRI);
55
  static WasiExpect<std::shared_ptr<VINode>>
56
  fromFd(int32_t Fd, __wasi_rights_t FRB, __wasi_rights_t FRI);
57
58
  static std::string canonicalGuest(std::string_view Path);
59
60
  static WasiExpect<std::shared_ptr<VINode>> bind(__wasi_rights_t FRB,
61
                                                  __wasi_rights_t FRI,
62
                                                  std::string Name,
63
                                                  std::string SystemPath);
64
65
0
  constexpr const std::string &name() const { return Name; }
66
67
  /// Provide file advisory information on a file descriptor.
68
  ///
69
  /// Note: This is similar to `posix_fadvise` in POSIX.
70
  ///
71
  /// @param[in] Offset The offset within the file to which the advisory
72
  /// applies.
73
  /// @param[in] Len The length of the region to which the advisory applies.
74
  /// @param[in] Advice The advice.
75
  /// @return Nothing or WASI error
76
  WasiExpect<void> fdAdvise(__wasi_filesize_t Offset, __wasi_filesize_t Len,
77
0
                            __wasi_advice_t Advice) const noexcept {
78
0
    if (!can(__WASI_RIGHTS_FD_ADVISE)) {
79
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
80
0
    }
81
0
    return Node.fdAdvise(Offset, Len, Advice);
82
0
  }
83
84
  /// Force the allocation of space in a file.
85
  ///
86
  /// Note: This is similar to `posix_fallocate` in POSIX.
87
  ///
88
  /// @param[in] Offset The offset at which to start the allocation.
89
  /// @param[in] Len The length of the area that is allocated.
90
  /// @return Nothing or WASI error
91
  WasiExpect<void> fdAllocate(__wasi_filesize_t Offset,
92
0
                              __wasi_filesize_t Len) const noexcept {
93
0
    if (!can(__WASI_RIGHTS_FD_ALLOCATE)) {
94
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
95
0
    }
96
0
    return Node.fdAllocate(Offset, Len);
97
0
  }
98
99
  /// Synchronize the data of a file to disk.
100
  ///
101
  /// Note: This is similar to `fdatasync` in POSIX.
102
  ///
103
  /// @return Nothing or WASI error
104
0
  WasiExpect<void> fdDatasync() const noexcept {
105
0
    if (!can(__WASI_RIGHTS_FD_DATASYNC)) {
106
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
107
0
    }
108
0
    return Node.fdDatasync();
109
0
  }
110
111
  /// Get the attributes of a file descriptor.
112
  ///
113
  /// Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well
114
  ///
115
  /// as additional fields.
116
  /// @param[out] FdStat Result.
117
  /// @return Nothing or WASI error
118
0
  WasiExpect<void> fdFdstatGet(__wasi_fdstat_t &FdStat) const noexcept {
119
0
    FdStat.fs_rights_base = FsRightsBase;
120
0
    FdStat.fs_rights_inheriting = FsRightsInheriting;
121
0
    return Node.fdFdstatGet(FdStat);
122
0
  }
123
124
  /// Adjust the flags associated with a file descriptor.
125
  ///
126
  /// Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX.
127
  ///
128
  /// @param[in] FdFlags The desired values of the file descriptor flags.
129
  /// @return Nothing or WASI error
130
0
  WasiExpect<void> fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept {
131
0
    __wasi_rights_t AdditionalRequiredRights = static_cast<__wasi_rights_t>(0);
132
133
0
    if (FdFlags & __WASI_FDFLAGS_DSYNC) {
134
0
      AdditionalRequiredRights |= __WASI_RIGHTS_FD_DATASYNC;
135
0
    }
136
0
    if (FdFlags & __WASI_FDFLAGS_RSYNC) {
137
0
      AdditionalRequiredRights |= __WASI_RIGHTS_FD_SYNC;
138
0
    }
139
0
    if (FdFlags & __WASI_FDFLAGS_SYNC) {
140
0
      AdditionalRequiredRights |= __WASI_RIGHTS_FD_SYNC;
141
0
    }
142
143
0
    if (!can(__WASI_RIGHTS_FD_FDSTAT_SET_FLAGS | AdditionalRequiredRights)) {
144
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
145
0
    }
146
0
    return Node.fdFdstatSetFlags(FdFlags);
147
0
  }
148
149
  /// Adjust the rights associated with a file descriptor.
150
  ///
151
  /// This can only be used to remove rights, and returns `errno::notcapable` if
152
  /// called in a way that would attempt to add rights
153
  ///
154
  /// @param[in] RightsBase The desired rights of the file descriptor.
155
  /// @param[in] RightsInheriting The desired rights of the file descriptor.
156
  /// @return Nothing or WASI error
157
  WasiExpect<void>
158
  fdFdstatSetRights(__wasi_rights_t RightsBase,
159
0
                    __wasi_rights_t RightsInheriting) noexcept {
160
0
    if (!can(RightsBase, RightsInheriting)) {
161
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
162
0
    }
163
0
    FsRightsBase = RightsBase;
164
0
    FsRightsInheriting = RightsInheriting;
165
166
0
    return {};
167
0
  }
168
169
  /// Return the attributes of an open file.
170
  ///
171
  /// @param[out] Filestat Result.
172
  /// @return Nothing or WASI error
173
0
  WasiExpect<void> fdFilestatGet(__wasi_filestat_t &Filestat) const noexcept {
174
0
    if (!can(__WASI_RIGHTS_FD_FILESTAT_GET)) {
175
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
176
0
    }
177
0
    return Node.fdFilestatGet(Filestat);
178
0
  }
179
180
  /// Adjust the size of an open file. If this increases the file's size, the
181
  /// extra bytes are filled with zeros.
182
  ///
183
  /// Note: This is similar to `ftruncate` in POSIX.
184
  ///
185
  /// @param[in] Size The desired file size.
186
  /// @return Nothing or WASI error
187
0
  WasiExpect<void> fdFilestatSetSize(__wasi_filesize_t Size) const noexcept {
188
0
    if (!can(__WASI_RIGHTS_FD_FILESTAT_SET_SIZE)) {
189
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
190
0
    }
191
0
    return Node.fdFilestatSetSize(Size);
192
0
  }
193
194
  /// Adjust the timestamps of an open file or directory.
195
  ///
196
  /// Note: This is similar to `futimens` in POSIX.
197
  ///
198
  /// @param[in] ATim The desired values of the data access timestamp.
199
  /// @param[in] MTim The desired values of the data modification timestamp.
200
  /// @param[in] FstFlags A bitmask indicating which timestamps to adjust.
201
  /// @return Nothing or WASI error
202
  WasiExpect<void>
203
  fdFilestatSetTimes(__wasi_timestamp_t ATim, __wasi_timestamp_t MTim,
204
0
                     __wasi_fstflags_t FstFlags) const noexcept {
205
0
    if (!can(__WASI_RIGHTS_FD_FILESTAT_SET_TIMES)) {
206
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
207
0
    }
208
0
    return Node.fdFilestatSetTimes(ATim, MTim, FstFlags);
209
0
  }
210
211
  /// Read from a file descriptor, without using and updating the file
212
  /// descriptor's offset.
213
  ///
214
  /// Note: This is similar to `preadv` in POSIX.
215
  ///
216
  /// @param[in] IOVs List of scatter/gather vectors in which to store data.
217
  /// @param[in] Offset The offset within the file at which to read.
218
  /// @param[out] NRead The number of bytes read.
219
  /// @return Nothing or WASI error
220
  WasiExpect<void> fdPread(Span<Span<uint8_t>> IOVs, __wasi_filesize_t Offset,
221
0
                           __wasi_size_t &NRead) const noexcept {
222
0
    if (!can(__WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_SEEK)) {
223
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
224
0
    }
225
0
    return Node.fdPread(IOVs, Offset, NRead);
226
0
  }
227
228
  /// Write to a file descriptor, without using and updating the file
229
  /// descriptor's offset.
230
  ///
231
  /// Note: This is similar to `pwritev` in POSIX.
232
  ///
233
  /// @param[in] IOVs List of scatter/gather vectors from which to retrieve
234
  /// data.
235
  /// @param[in] Offset The offset within the file at which to write.
236
  /// @param[out] NWritten The number of bytes written.
237
  /// @return Nothing or WASI error
238
  WasiExpect<void> fdPwrite(Span<Span<const uint8_t>> IOVs,
239
                            __wasi_filesize_t Offset,
240
0
                            __wasi_size_t &NWritten) const noexcept {
241
0
    if (!can(__WASI_RIGHTS_FD_WRITE | __WASI_RIGHTS_FD_SEEK)) {
242
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
243
0
    }
244
0
    return Node.fdPwrite(IOVs, Offset, NWritten);
245
0
  }
246
247
  /// Read from a file descriptor.
248
  ///
249
  /// Note: This is similar to `readv` in POSIX.
250
  ///
251
  /// @param[in] IOVs List of scatter/gather vectors to which to store data.
252
  /// @param[out] NRead The number of bytes read.
253
  /// @return Nothing or WASI error
254
  WasiExpect<void> fdRead(Span<Span<uint8_t>> IOVs,
255
0
                          __wasi_size_t &NRead) const noexcept {
256
0
    if (!can(__WASI_RIGHTS_FD_READ)) {
257
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
258
0
    }
259
0
    return Node.fdRead(IOVs, NRead);
260
0
  }
261
262
  /// Read directory entries from a directory.
263
  ///
264
  /// When successful, the contents of the output buffer consist of a sequence
265
  /// of directory entries. Each directory entry consists of a `dirent` object,
266
  /// followed by `dirent::d_namlen` bytes holding the name of the directory
267
  /// entry.
268
  ///
269
  /// This function fills the output buffer as much as possible,
270
  /// potentially truncating the last directory entry. This allows the caller to
271
  /// grow its read buffer size in case it's too small to fit a single large
272
  /// directory entry, or skip the oversized directory entry.
273
  ///
274
  /// @param[out] Buffer The buffer where directory entries are stored.
275
  /// @param[in] Cookie The location within the directory to start reading
276
  /// @param[out] Size The number of bytes stored in the read buffer. If less
277
  /// than the size of the read buffer, the end of the directory has been
278
  /// reached.
279
  /// @return Nothing or WASI error
280
  WasiExpect<void> fdReaddir(Span<uint8_t> Buffer, __wasi_dircookie_t Cookie,
281
0
                             __wasi_size_t &Size) noexcept {
282
0
    if (!can(__WASI_RIGHTS_FD_READDIR)) {
283
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
284
0
    }
285
0
    return Node.fdReaddir(Buffer, Cookie, Size);
286
0
  }
287
288
  /// Move the offset of a file descriptor.
289
  ///
290
  /// Note: This is similar to `lseek` in POSIX.
291
  ///
292
  /// @param[in] Offset The number of bytes to move.
293
  /// @param[in] Whence The base from which the offset is relative.
294
  /// @param[out] Size The new offset of the file descriptor, relative to the
295
  /// start of the file.
296
  /// @return Nothing or WASI error
297
  WasiExpect<void> fdSeek(__wasi_filedelta_t Offset, __wasi_whence_t Whence,
298
0
                          __wasi_filesize_t &Size) const noexcept {
299
0
    if (!can(__WASI_RIGHTS_FD_SEEK)) {
300
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
301
0
    }
302
0
    return Node.fdSeek(Offset, Whence, Size);
303
0
  }
304
305
  /// Synchronize the data and metadata of a file to disk.
306
  ///
307
  /// Note: This is similar to `fsync` in POSIX.
308
  ///
309
  /// @return Nothing or WASI error
310
0
  WasiExpect<void> fdSync() const noexcept {
311
0
    if (!can(__WASI_RIGHTS_FD_SYNC)) {
312
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
313
0
    }
314
0
    return Node.fdSync();
315
0
  }
316
317
  /// Return the current offset of a file descriptor.
318
  ///
319
  /// Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX.
320
  ///
321
  /// @param[out] Size The current offset of the file descriptor, relative to
322
  /// the start of the file.
323
  /// @return Nothing or WASI error
324
0
  WasiExpect<void> fdTell(__wasi_filesize_t &Size) const noexcept {
325
0
    if (!can(__WASI_RIGHTS_FD_TELL)) {
326
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
327
0
    }
328
0
    return Node.fdTell(Size);
329
0
  }
330
331
  /// Write to a file descriptor.
332
  ///
333
  /// Note: This is similar to `writev` in POSIX.
334
  ///
335
  /// @param[in] IOVs List of scatter/gather vectors from which to retrieve
336
  /// data.
337
  /// @param[out] NWritten The number of bytes written.
338
  /// @return Nothing or WASI error
339
  WasiExpect<void> fdWrite(Span<Span<const uint8_t>> IOVs,
340
0
                           __wasi_size_t &NWritten) const noexcept {
341
0
    if (!can(__WASI_RIGHTS_FD_WRITE)) {
342
0
      return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
343
0
    }
344
0
    return Node.fdWrite(IOVs, NWritten);
345
0
  }
346
347
  /// Get the native handler.
348
  ///
349
  /// Note: Users should cast this native handler to corresponding types
350
  /// on different operating systems. E.g. int on POSIX or void * on Windows
351
  ///
352
  /// @return The native handler in uint64_t.
353
0
  WasiExpect<uint64_t> getNativeHandler() const noexcept {
354
0
    return Node.getNativeHandler();
355
0
  }
356
357
  /// Create a directory.
358
  ///
359
  /// Note: This is similar to `mkdirat` in POSIX.
360
  ///
361
  /// @param[in] Fd The working directory at which the resolution of the path
362
  /// starts.
363
  /// @param[in] Path The path at which to create the directory.
364
  /// @return Nothing or WASI error
365
  static WasiExpect<void> pathCreateDirectory(std::shared_ptr<VINode> Fd,
366
                                              std::string_view Path);
367
368
  /// Return the attributes of a file or directory.
369
  ///
370
  /// Note: This is similar to `stat` in POSIX.
371
  ///
372
  /// @param[in] Fd The working directory at which the resolution of the path
373
  /// starts.
374
  /// @param[in] Path The path of the file or directory to inspect.
375
  /// @param[in] Flags Flags determining the method of how the path is resolved.
376
  /// @param[out] Filestat The buffer where the file's attributes are stored.
377
  /// @return Nothing or WASI error
378
  static WasiExpect<void> pathFilestatGet(std::shared_ptr<VINode> Fd,
379
                                          std::string_view Path,
380
                                          __wasi_lookupflags_t Flags,
381
                                          __wasi_filestat_t &Filestat);
382
383
  /// Adjust the timestamps of a file or directory.
384
  ///
385
  /// Note: This is similar to `utimensat` in POSIX.
386
  ///
387
  /// @param[in] Fd The working directory at which the resolution of the path
388
  /// starts.
389
  /// @param[in] Path The path of the file or directory to inspect.
390
  /// @param[in] Flags Flags determining the method of how the path is resolved.
391
  /// @param[in] ATim The desired values of the data access timestamp.
392
  /// @param[in] MTim The desired values of the data modification timestamp.
393
  /// @param[in] FstFlags A bitmask indicating which timestamps to adjust.
394
  /// @return Nothing or WASI error
395
  static WasiExpect<void>
396
  pathFilestatSetTimes(std::shared_ptr<VINode> Fd, std::string_view Path,
397
                       __wasi_lookupflags_t Flags, __wasi_timestamp_t ATim,
398
                       __wasi_timestamp_t MTim, __wasi_fstflags_t FstFlags);
399
400
  /// Create a hard link.
401
  ///
402
  /// Note: This is similar to `linkat` in POSIX.
403
  ///
404
  /// @param[in] Old The working directory at which the resolution of the old
405
  /// path starts.
406
  /// @param[in] OldPath The source path from which to link.
407
  /// @param[in] New The working directory at which the resolution of the new
408
  /// path starts.
409
  /// @param[in] NewPath The destination path at which to create the hard link.
410
  /// @param[in] LookupFlags Flags determining the method of how the path is
411
  /// resolved.
412
  /// @return Nothing or WASI error
413
  static WasiExpect<void> pathLink(std::shared_ptr<VINode> Old,
414
                                   std::string_view OldPath,
415
                                   std::shared_ptr<VINode> New,
416
                                   std::string_view NewPath,
417
                                   __wasi_lookupflags_t LookupFlags);
418
419
  /// Open a file or directory.
420
  ///
421
  /// The returned file descriptor is not guaranteed to be the lowest-numbered
422
  /// file descriptor not currently open; it is randomized to prevent
423
  /// applications from depending on making assumptions about indexes, since
424
  /// this is error-prone in multi-threaded contexts. The returned file
425
  /// descriptor is guaranteed to be less than 2**31.
426
  ///
427
  /// Note: This is similar to `openat` in POSIX.
428
  ///
429
  /// @param[in] Fd The working directory at which the resolution of the path
430
  /// starts.
431
  /// @param[in] Path The relative path of the file or directory to open,
432
  /// relative to the `path_open::fd` directory.
433
  /// @param[in] LookupFlags Flags determining the method of how the path is
434
  /// resolved.
435
  /// @param[in] OpenFlags The method by which to open the file.
436
  /// @param[in] FsRightsBase The initial rights of the newly created file
437
  /// descriptor. The implementation is allowed to return a file descriptor with
438
  /// fewer rights than specified, if and only if those rights do not apply to
439
  /// the type of file being opened. The *base* rights are rights that will
440
  /// apply to operations using the file descriptor itself.
441
  /// @param[in] FsRightsInheriting The initial rights of the newly created file
442
  /// descriptor. The implementation is allowed to return a file descriptor with
443
  /// fewer rights than specified, if and only if those rights do not apply to
444
  /// the type of file being opened. The *inheriting* rights are rights that
445
  /// apply to file descriptors derived from it.
446
  /// @param[in] FdFlags The method by which to open the file.
447
  /// @return The file descriptor of the file that has been opened, or WASI
448
  /// error.
449
  static WasiExpect<std::shared_ptr<VINode>>
450
  pathOpen(std::shared_ptr<VINode> Fd, std::string_view Path,
451
           __wasi_lookupflags_t LookupFlags, __wasi_oflags_t OpenFlags,
452
           __wasi_rights_t FsRightsBase, __wasi_rights_t FsRightsInheriting,
453
           __wasi_fdflags_t FdFlags);
454
455
  /// Read the contents of a symbolic link.
456
  ///
457
  /// Note: This is similar to `readlinkat` in POSIX.
458
  ///
459
  /// @param[in] Fd The working directory at which the resolution of the path
460
  /// starts.
461
  /// @param[in] Path The path of the symbolic link from which to read.
462
  /// @param[out] Buffer The buffer to which to write the contents of the
463
  /// symbolic link.
464
  /// @param[out] NRead The number of bytes read.
465
  /// @return Nothing or WASI error.
466
  static WasiExpect<void> pathReadlink(std::shared_ptr<VINode> Fd,
467
                                       std::string_view Path, Span<char> Buffer,
468
                                       __wasi_size_t &NRead);
469
470
  /// Remove a directory.
471
  ///
472
  /// Return `errno::notempty` if the directory is not empty.
473
  ///
474
  /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
475
  ///
476
  /// @param[in] Fd The working directory at which the resolution of the path
477
  /// starts.
478
  /// @param[in] Path The path to a directory to remove.
479
  /// @return Nothing or WASI error.
480
  static WasiExpect<void> pathRemoveDirectory(std::shared_ptr<VINode> Fd,
481
                                              std::string_view Path);
482
483
  /// Rename a file or directory.
484
  ///
485
  /// Note: This is similar to `renameat` in POSIX.
486
  ///
487
  /// @param[in] Old The working directory at which the resolution of the old
488
  /// path starts.
489
  /// @param[in] OldPath The source path of the file or directory to rename.
490
  /// @param[in] New The working directory at which the resolution of the new
491
  /// path starts.
492
  /// @param[in] NewPath The destination path to which to rename the file or
493
  /// directory.
494
  /// @return Nothing or WASI error.
495
  static WasiExpect<void> pathRename(std::shared_ptr<VINode> Old,
496
                                     std::string_view OldPath,
497
                                     std::shared_ptr<VINode> New,
498
                                     std::string_view NewPath);
499
500
  /// Create a symbolic link.
501
  ///
502
  /// Note: This is similar to `symlinkat` in POSIX.
503
  ///
504
  /// @param[in] OldPath The contents of the symbolic link.
505
  /// @param[in] New The working directory at which the resolution of the new
506
  /// path starts.
507
  /// @param[in] NewPath The destination path at which to create the symbolic
508
  /// link.
509
  /// @return Nothing or WASI error
510
  static WasiExpect<void> pathSymlink(std::string_view OldPath,
511
                                      std::shared_ptr<VINode> New,
512
                                      std::string_view NewPath);
513
514
  /// Unlink a file.
515
  ///
516
  /// Return `errno::isdir` if the path refers to a directory.
517
  ///
518
  /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
519
  ///
520
  /// @param[in] Fd The working directory at which the resolution of the path
521
  /// starts.
522
  /// @param[in] Path The path to a file to unlink.
523
  /// @return Nothing or WASI error.
524
  static WasiExpect<void> pathUnlinkFile(std::shared_ptr<VINode> Fd,
525
                                         std::string_view Path);
526
527
  static WasiExpect<void>
528
  getAddrinfo(std::string_view Node, std::string_view Service,
529
              const __wasi_addrinfo_t &Hint, uint32_t MaxResLength,
530
              Span<__wasi_addrinfo_t *> WasiAddrinfoArray,
531
              Span<__wasi_sockaddr_t *> WasiSockaddrArray,
532
              Span<char *> AiAddrSaDataArray, Span<char *> AiCanonnameArray,
533
              /*Out*/ __wasi_size_t &ResLength) noexcept;
534
535
  static WasiExpect<std::shared_ptr<VINode>>
536
  sockOpen(__wasi_address_family_t SysDomain, __wasi_sock_type_t SockType);
537
538
  WasiExpect<void> sockBind(__wasi_address_family_t AddressFamily,
539
                            Span<const uint8_t> Address,
540
0
                            uint16_t Port) noexcept {
541
0
    return Node.sockBind(AddressFamily, Address, Port);
542
0
  }
543
544
0
  WasiExpect<void> sockListen(int32_t Backlog) noexcept {
545
0
    return Node.sockListen(Backlog);
546
0
  }
547
548
  WasiExpect<std::shared_ptr<VINode>> sockAccept(__wasi_fdflags_t FdFlags);
549
550
  WasiExpect<void> sockConnect(__wasi_address_family_t AddressFamily,
551
                               Span<const uint8_t> Address,
552
0
                               uint16_t Port) noexcept {
553
0
    return Node.sockConnect(AddressFamily, Address, Port);
554
0
  }
555
556
  /// Receive a message from a socket.
557
  ///
558
  /// Note: This is similar to `recv` in POSIX, though it also supports reading
559
  /// the data into multiple buffers in the manner of `readv`.
560
  ///
561
  /// @param[in] RiData List of scatter/gather vectors to which to store data.
562
  /// @param[in] RiFlags Message flags.
563
  /// @param[out] NRead Return the number of bytes stored in RiData.
564
  /// @param[out] RoFlags Return message flags.
565
  /// @return Nothing or WASI error.
566
  WasiExpect<void> sockRecv(Span<Span<uint8_t>> RiData,
567
                            __wasi_riflags_t RiFlags, __wasi_size_t &NRead,
568
0
                            __wasi_roflags_t &RoFlags) const noexcept {
569
0
    return Node.sockRecv(RiData, RiFlags, NRead, RoFlags);
570
0
  }
571
572
  /// Receive a message from a socket.
573
  ///
574
  /// Note: This is similar to `recvfrom` in POSIX, though it also supports
575
  /// reading the data into multiple buffers in the manner of `readv`.
576
  ///
577
  /// @param[in] RiData List of scatter/gather vectors to which to store data.
578
  /// @param[in] RiFlags Message flags.
579
  /// @param[out] AddressFamilyPtr The pointer to store address family.
580
  /// @param[out] Address The buffer to store address.
581
  /// @param[out] PortPtr The pointer to store port.
582
  /// @param[out] NRead Return the number of bytes stored in RiData.
583
  /// @param[out] RoFlags Return message flags.
584
  /// @return Nothing or WASI error.
585
  WasiExpect<void> sockRecvFrom(Span<Span<uint8_t>> RiData,
586
                                __wasi_riflags_t RiFlags,
587
                                __wasi_address_family_t *AddressFamilyPtr,
588
                                Span<uint8_t> Address, uint16_t *PortPtr,
589
                                __wasi_size_t &NRead,
590
0
                                __wasi_roflags_t &RoFlags) const noexcept {
591
0
    return Node.sockRecvFrom(RiData, RiFlags, AddressFamilyPtr, Address,
592
0
                             PortPtr, NRead, RoFlags);
593
0
  }
594
595
  /// Send a message on a socket.
596
  ///
597
  /// Note: This is similar to `send` in POSIX, though it also supports writing
598
  /// the data from multiple buffers in the manner of `writev`.
599
  ///
600
  /// @param[in] SiData List of scatter/gather vectors to which to retrieve
601
  /// data.
602
  /// @param[in] SiFlags Message flags.
603
  /// @param[out] NWritten The number of bytes transmitted.
604
  /// @return Nothing or WASI error
605
  WasiExpect<void> sockSend(Span<Span<const uint8_t>> SiData,
606
                            __wasi_siflags_t SiFlags,
607
0
                            __wasi_size_t &NWritten) const noexcept {
608
0
    return Node.sockSend(SiData, SiFlags, NWritten);
609
0
  }
610
611
  /// Send a message on a socket.
612
  ///
613
  /// Note: This is similar to `send` in POSIX, though it also supports writing
614
  /// the data from multiple buffers in the manner of `writev`.
615
  ///
616
  /// @param[in] SiData List of scatter/gather vectors to which to retrieve
617
  /// data.
618
  /// @param[in] SiFlags Message flags.
619
  /// @param[in] AddressFamily Address family of the target.
620
  /// @param[in] Address Address of the target.
621
  /// @param[in] Port Connected port.
622
  /// @param[out] NWritten The number of bytes transmitted.
623
  /// @return Nothing or WASI error
624
  WasiExpect<void> sockSendTo(Span<Span<const uint8_t>> SiData,
625
                              __wasi_siflags_t SiFlags,
626
                              __wasi_address_family_t AddressFamily,
627
                              Span<const uint8_t> Address, uint16_t Port,
628
0
                              __wasi_size_t &NWritten) const noexcept {
629
0
    return Node.sockSendTo(SiData, SiFlags, AddressFamily, Address, Port,
630
0
                           NWritten);
631
0
  }
632
633
  /// Shut down socket send and receive channels.
634
  ///
635
  /// Note: This is similar to `shutdown` in POSIX.
636
  ///
637
  /// @param[in] SdFlags Which channels on the socket to shut down.
638
  /// @return Nothing or WASI error
639
0
  WasiExpect<void> sockShutdown(__wasi_sdflags_t SdFlags) const noexcept {
640
0
    return Node.sockShutdown(SdFlags);
641
0
  }
642
643
  WasiExpect<void> sockGetOpt(__wasi_sock_opt_level_t SockOptLevel,
644
                              __wasi_sock_opt_so_t SockOptName,
645
0
                              Span<uint8_t> &Flag) const noexcept {
646
0
    return Node.sockGetOpt(SockOptLevel, SockOptName, Flag);
647
0
  }
648
649
  WasiExpect<void> sockSetOpt(__wasi_sock_opt_level_t SockOptLevel,
650
                              __wasi_sock_opt_so_t SockOptName,
651
0
                              Span<const uint8_t> Flag) const noexcept {
652
0
    return Node.sockSetOpt(SockOptLevel, SockOptName, Flag);
653
0
  }
654
655
  WasiExpect<void> sockGetLocalAddr(__wasi_address_family_t *AddressFamilyPtr,
656
                                    Span<uint8_t> Address,
657
0
                                    uint16_t *PortPtr) const noexcept {
658
0
    return Node.sockGetLocalAddr(AddressFamilyPtr, Address, PortPtr);
659
0
  }
660
661
  WasiExpect<void> sockGetPeerAddr(__wasi_address_family_t *AddressFamilyPtr,
662
                                   Span<uint8_t> Address,
663
0
                                   uint16_t *PortPtr) const noexcept {
664
0
    return Node.sockGetPeerAddr(AddressFamilyPtr, Address, PortPtr);
665
0
  }
666
667
0
  __wasi_rights_t fsRightsBase() const noexcept { return FsRightsBase; }
668
669
0
  __wasi_rights_t fsRightsInheriting() const noexcept {
670
0
    return FsRightsInheriting;
671
0
  }
672
673
  /// Check if this vinode is a directory.
674
0
  bool isDirectory() const noexcept { return Node.isDirectory(); }
675
676
  /// Check if current user has execute permission on this vinode directory.
677
0
  bool canBrowse() const noexcept { return Node.canBrowse(); }
678
679
  /// Check if this vinode is a symbolic link.
680
0
  bool isSymlink() const noexcept { return Node.isSymlink(); }
681
682
0
  static constexpr __wasi_rights_t imply(__wasi_rights_t Rights) noexcept {
683
0
    if (Rights & __WASI_RIGHTS_FD_SEEK) {
684
0
      Rights |= __WASI_RIGHTS_FD_TELL;
685
0
    }
686
0
    if (Rights & __WASI_RIGHTS_FD_SYNC) {
687
0
      Rights |= __WASI_RIGHTS_FD_DATASYNC;
688
0
    }
689
0
    return Rights;
690
0
  }
691
692
  constexpr bool can(__wasi_rights_t RequiredRights,
693
                     __wasi_rights_t RequiredInheritingRights =
694
0
                         static_cast<__wasi_rights_t>(0)) const noexcept {
695
0
    const auto Base = imply(FsRightsBase);
696
0
    const auto Inheriting = imply(FsRightsInheriting);
697
0
    return (Base & RequiredRights) == RequiredRights &&
698
0
           (Inheriting & RequiredInheritingRights) == RequiredInheritingRights;
699
0
  }
700
701
private:
702
  INode Node;
703
  __wasi_rights_t FsRightsBase;
704
  __wasi_rights_t FsRightsInheriting;
705
  std::string Name;
706
707
  friend class VPoller;
708
709
  /// Open path without resolve.
710
  /// @param Path Path, contains one element only.
711
  /// @param OpenFlags WASI open flags.
712
  /// @return VINode found, or WASI error.
713
  WasiExpect<std::shared_ptr<VINode>>
714
  directOpen(std::string_view Path, __wasi_oflags_t OpenFlags,
715
             __wasi_fdflags_t FdFlags, VFS::Flags VFSFlags,
716
             __wasi_rights_t RightsBase, __wasi_rights_t RightsInheriting);
717
718
  /// Resolve path until last element.
719
  /// @param[in,out] Fd Fd. Return parent of last part if found.
720
  /// @param[in,out] Path path. Return last part of path if found.
721
  /// @param[in] LookupFlags WASI lookup flags.
722
  /// @param[in] VFSFlags Internal lookup flags.
723
  /// @param[in] LinkCount Counting symbolic link lookup times.
724
  /// @param[in] FollowTrailingSlashes If Path ends with slash, open it and set
725
  /// Path to ".".
726
  /// @return Allocated buffer, or WASI error.
727
  static WasiExpect<std::vector<char>> resolvePath(
728
      std::shared_ptr<VINode> &Fd, std::string_view &Path,
729
      __wasi_lookupflags_t LookupFlags = __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,
730
      VFS::Flags VFSFlags = static_cast<VFS::Flags>(0), uint8_t LinkCount = 0,
731
      bool FollowTrailingSlashes = true);
732
733
  /// Proxy function for `resolvePath`.
734
  /// @param[in,out] Fd Fd. Return parent of last part if found.
735
  /// @param[in,out] Path path. Return last part of path if found.
736
  /// @param[in] FollowTrailingSlashes If Path ends with slash, open it and set
737
  /// Path to ".".
738
  /// @return Allocated buffer, or WASI error.
739
  static inline WasiExpect<std::vector<char>>
740
  resolvePath(std::shared_ptr<VINode> &Fd, std::string_view &Path,
741
0
              bool FollowTrailingSlashes) {
742
0
    return resolvePath(Fd, Path, __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW,
743
0
                       static_cast<VFS::Flags>(0), 0, FollowTrailingSlashes);
744
0
  }
745
};
746
747
class VPoller : protected Poller {
748
public:
749
  using Poller::clock;
750
  using Poller::close;
751
  using Poller::error;
752
  using Poller::ok;
753
  using Poller::Poller;
754
  using Poller::prepare;
755
  using Poller::reset;
756
  using Poller::result;
757
  using Poller::wait;
758
759
  void read(std::shared_ptr<VINode> Fd, TriggerType Trigger,
760
0
            __wasi_userdata_t UserData) noexcept {
761
0
    if (!Fd->can(__WASI_RIGHTS_POLL_FD_READWRITE) &&
762
0
        !Fd->can(__WASI_RIGHTS_FD_READ)) {
763
0
      Poller::error(UserData, __WASI_ERRNO_NOTCAPABLE,
764
0
                    __WASI_EVENTTYPE_FD_READ);
765
0
    } else {
766
0
      Poller::read(Fd->Node, Trigger, UserData);
767
0
    }
768
0
  }
769
770
  void write(std::shared_ptr<VINode> Fd, TriggerType Trigger,
771
0
             __wasi_userdata_t UserData) noexcept {
772
0
    if (!Fd->can(__WASI_RIGHTS_POLL_FD_READWRITE) &&
773
0
        !Fd->can(__WASI_RIGHTS_FD_WRITE)) {
774
0
      Poller::error(UserData, __WASI_ERRNO_NOTCAPABLE,
775
0
                    __WASI_EVENTTYPE_FD_WRITE);
776
0
    } else {
777
0
      Poller::write(Fd->Node, Trigger, UserData);
778
0
    }
779
0
  }
780
781
0
  void close(std::shared_ptr<VINode> Fd) noexcept { Poller::close(Fd->Node); }
782
};
783
784
} // namespace WASI
785
} // namespace Host
786
} // namespace WasmEdge