Coverage Report

Created: 2025-08-29 06:29

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