Coverage Report

Created: 2025-07-01 06:18

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