Coverage Report

Created: 2026-06-30 06:10

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/host/wasi/vinode.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "host/wasi/vinode.h"
5
#include "common/errcode.h"
6
#include "common/spdlog.h"
7
#include "host/wasi/environ.h"
8
#include "host/wasi/vfs.h"
9
#include <algorithm>
10
#include <cstddef>
11
#include <numeric>
12
#include <string>
13
14
using namespace std::literals;
15
16
namespace WasmEdge {
17
namespace Host {
18
namespace WASI {
19
20
namespace {
21
22
static inline constexpr const uint8_t kMaxNestedLinks = 8;
23
24
}
25
26
VINode::VINode(INode Node, __wasi_rights_t FRB, __wasi_rights_t FRI,
27
               std::string N)
28
0
    : Node(std::move(Node)), FsRightsBase(FRB), FsRightsInheriting(FRI),
29
0
      Name(std::move(N)) {}
30
31
std::shared_ptr<VINode> VINode::stdIn(__wasi_rights_t FRB,
32
0
                                      __wasi_rights_t FRI) {
33
0
  return std::make_shared<VINode>(INode::stdIn(), FRB, FRI);
34
0
}
35
36
std::shared_ptr<VINode> VINode::stdOut(__wasi_rights_t FRB,
37
0
                                       __wasi_rights_t FRI) {
38
0
  return std::make_shared<VINode>(INode::stdOut(), FRB, FRI);
39
0
}
40
41
std::shared_ptr<VINode> VINode::stdErr(__wasi_rights_t FRB,
42
0
                                       __wasi_rights_t FRI) {
43
0
  return std::make_shared<VINode>(INode::stdErr(), FRB, FRI);
44
0
}
45
46
WasiExpect<std::shared_ptr<VINode>>
47
0
VINode::fromFd(int32_t Fd, __wasi_rights_t FRB, __wasi_rights_t FRI) {
48
0
  auto NodeResult = INode::fromFd(Fd);
49
0
  if (!NodeResult) {
50
0
    return WasiUnexpect(NodeResult.error());
51
0
  }
52
0
  return std::make_shared<VINode>(std::move(*NodeResult), FRB, FRI);
53
0
}
54
0
std::string VINode::canonicalGuest(std::string_view Path) {
55
0
  std::vector<std::string_view> Parts;
56
57
0
  while (!Path.empty() && Path.front() == '/') {
58
0
    Path = Path.substr(1);
59
0
  }
60
0
  while (!Path.empty()) {
61
0
    auto Slash = Path.find('/');
62
0
    const auto Part = Path.substr(0, Slash);
63
0
    auto Remain = Path.substr(Part.size());
64
0
    while (!Remain.empty() && Remain.front() == '/') {
65
0
      Remain = Remain.substr(1);
66
0
    }
67
0
    if (Part.front() == '.' && Part.size() == 2 && Part[1] == '.') {
68
0
      if (!Parts.empty()) {
69
0
        Parts.pop_back();
70
0
      }
71
0
    } else if (Part.front() != '.' || Parts.size() != 1) {
72
0
      Parts.push_back(Part);
73
0
    }
74
0
    if (Remain.empty()) {
75
0
      break;
76
0
    }
77
0
    Path = Remain;
78
0
  }
79
0
  if (Parts.empty()) {
80
0
    Parts.push_back({});
81
0
  }
82
83
0
  std::string Result;
84
0
  Result.reserve(std::accumulate(
85
0
      Parts.begin(), Parts.end(), Parts.size(),
86
0
      [](size_t L, std::string_view P) { return L + P.size(); }));
87
0
  std::for_each(Parts.begin(), Parts.end(), [&Result](std::string_view P) {
88
0
    Result += P;
89
0
    Result += '/';
90
0
  });
91
0
  if (!Result.empty()) {
92
0
    Result.pop_back();
93
0
  }
94
95
0
  return Result;
96
0
}
97
98
WasiExpect<std::shared_ptr<VINode>> VINode::bind(__wasi_rights_t FRB,
99
                                                 __wasi_rights_t FRI,
100
                                                 std::string Name,
101
0
                                                 std::string SystemPath) {
102
0
  EXPECTED_TRY(auto Node,
103
0
               INode::open(std::move(SystemPath), __WASI_OFLAGS_DIRECTORY,
104
0
                           __wasi_fdflags_t(0), VFS::Read));
105
0
  return std::make_shared<VINode>(std::move(Node), FRB, FRI, std::move(Name));
106
0
}
107
108
WasiExpect<void> VINode::pathCreateDirectory(std::shared_ptr<VINode> Fd,
109
0
                                             std::string_view Path) {
110
0
  if (!Fd->can(__WASI_RIGHTS_PATH_CREATE_DIRECTORY)) {
111
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
112
0
  }
113
0
  EXPECTED_TRY(auto Buffer, resolvePath(Fd, Path, false));
114
0
  return Fd->Node.pathCreateDirectory(std::string(Path));
115
0
}
116
117
WasiExpect<void> VINode::pathFilestatGet(std::shared_ptr<VINode> Fd,
118
                                         std::string_view Path,
119
                                         __wasi_lookupflags_t Flags,
120
0
                                         __wasi_filestat_t &Filestat) {
121
0
  if (!Fd->can(__WASI_RIGHTS_PATH_FILESTAT_GET)) {
122
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
123
0
  }
124
0
  EXPECTED_TRY(auto Buffer, resolvePath(Fd, Path, Flags));
125
0
  return Fd->Node.pathFilestatGet(std::string(Path), Filestat);
126
0
}
127
128
WasiExpect<void> VINode::pathFilestatSetTimes(std::shared_ptr<VINode> Fd,
129
                                              std::string_view Path,
130
                                              __wasi_lookupflags_t Flags,
131
                                              __wasi_timestamp_t ATim,
132
                                              __wasi_timestamp_t MTim,
133
0
                                              __wasi_fstflags_t FstFlags) {
134
0
  if (!Fd->can(__WASI_RIGHTS_PATH_FILESTAT_SET_TIMES)) {
135
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
136
0
  }
137
0
  EXPECTED_TRY(auto Buffer, resolvePath(Fd, Path, Flags));
138
0
  return Fd->Node.pathFilestatSetTimes(std::string(Path), ATim, MTim, FstFlags);
139
0
}
140
141
WasiExpect<void> VINode::pathLink(std::shared_ptr<VINode> Old,
142
                                  std::string_view OldPath,
143
                                  std::shared_ptr<VINode> New,
144
                                  std::string_view NewPath,
145
0
                                  __wasi_lookupflags_t LookupFlags) {
146
0
  if (unlikely(!New)) {
147
0
    return WasiUnexpect(__WASI_ERRNO_BADF);
148
0
  }
149
0
  if (!Old->can(__WASI_RIGHTS_PATH_LINK_SOURCE)) {
150
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
151
0
  }
152
0
  if (!New->can(__WASI_RIGHTS_PATH_LINK_TARGET)) {
153
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
154
0
  }
155
0
  EXPECTED_TRY(auto OldBuffer, resolvePath(Old, OldPath, LookupFlags));
156
0
  EXPECTED_TRY(auto NewBuffer, resolvePath(New, NewPath, LookupFlags));
157
158
0
  return INode::pathLink(Old->Node, std::string(OldPath), New->Node,
159
0
                         std::string(NewPath));
160
0
}
161
162
WasiExpect<std::shared_ptr<VINode>>
163
VINode::pathOpen(std::shared_ptr<VINode> Fd, std::string_view Path,
164
                 __wasi_lookupflags_t LookupFlags, __wasi_oflags_t OpenFlags,
165
                 __wasi_rights_t FsRightsBase,
166
0
                 __wasi_rights_t FsRightsInheriting, __wasi_fdflags_t FdFlags) {
167
0
  if (OpenFlags & __WASI_OFLAGS_DIRECTORY) {
168
0
    FsRightsBase &= ~__WASI_RIGHTS_FD_SEEK;
169
0
  } else {
170
0
    FsRightsBase &= ~__WASI_RIGHTS_PATH_FILESTAT_GET;
171
0
    FsRightsInheriting &= ~__WASI_RIGHTS_PATH_FILESTAT_GET;
172
0
  }
173
174
0
  __wasi_rights_t RequiredRights = __WASI_RIGHTS_PATH_OPEN;
175
0
  __wasi_rights_t RequiredInheritingRights = FsRightsBase | FsRightsInheriting;
176
0
  const bool Read =
177
0
      (FsRightsBase & (__WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_READDIR)) != 0;
178
0
  const bool Write =
179
0
      (FsRightsBase &
180
0
       (__WASI_RIGHTS_FD_DATASYNC | __WASI_RIGHTS_FD_WRITE |
181
0
        __WASI_RIGHTS_FD_ALLOCATE | __WASI_RIGHTS_FD_FILESTAT_SET_SIZE)) != 0;
182
183
0
  if (OpenFlags & __WASI_OFLAGS_CREAT) {
184
0
    RequiredRights |= __WASI_RIGHTS_PATH_CREATE_FILE;
185
0
  }
186
0
  if (OpenFlags & __WASI_OFLAGS_TRUNC) {
187
0
    RequiredRights |= __WASI_RIGHTS_PATH_FILESTAT_SET_SIZE;
188
0
  }
189
0
  if (FdFlags & __WASI_FDFLAGS_RSYNC) {
190
0
    RequiredInheritingRights |= __WASI_RIGHTS_FD_SYNC;
191
0
  }
192
0
  if (FdFlags & __WASI_FDFLAGS_DSYNC) {
193
0
    RequiredInheritingRights |= __WASI_RIGHTS_FD_DATASYNC;
194
0
  }
195
196
0
  if (!Fd->can(RequiredRights, RequiredInheritingRights)) {
197
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
198
0
  }
199
0
  EXPECTED_TRY(auto Buffer, resolvePath(Fd, Path, LookupFlags));
200
0
  VFS::Flags VFSFlags = static_cast<VFS::Flags>(0);
201
0
  if (Read) {
202
0
    VFSFlags |= VFS::Read;
203
0
  }
204
0
  if (Write) {
205
0
    VFSFlags |= VFS::Write;
206
0
  }
207
0
  return Fd->directOpen(Path, OpenFlags, FdFlags, VFSFlags, FsRightsBase,
208
0
                        FsRightsInheriting);
209
0
}
210
211
WasiExpect<void> VINode::pathReadlink(std::shared_ptr<VINode> Fd,
212
                                      std::string_view Path, Span<char> Buffer,
213
0
                                      __wasi_size_t &NRead) {
214
0
  if (!Fd->can(__WASI_RIGHTS_PATH_READLINK)) {
215
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
216
0
  }
217
0
  EXPECTED_TRY(auto PathBuffer,
218
0
               resolvePath(Fd, Path, static_cast<__wasi_lookupflags_t>(0)));
219
220
0
  return Fd->Node.pathReadlink(std::string(Path), Buffer, NRead);
221
0
}
222
223
WasiExpect<void> VINode::pathRemoveDirectory(std::shared_ptr<VINode> Fd,
224
0
                                             std::string_view Path) {
225
0
  if (!Fd->can(__WASI_RIGHTS_PATH_REMOVE_DIRECTORY)) {
226
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
227
0
  }
228
0
  EXPECTED_TRY(auto Buffer, resolvePath(Fd, Path, false));
229
230
0
  return Fd->Node.pathRemoveDirectory(std::string(Path));
231
0
}
232
233
WasiExpect<void> VINode::pathRename(std::shared_ptr<VINode> Old,
234
                                    std::string_view OldPath,
235
                                    std::shared_ptr<VINode> New,
236
0
                                    std::string_view NewPath) {
237
0
  if (!Old->can(__WASI_RIGHTS_PATH_RENAME_SOURCE)) {
238
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
239
0
  }
240
0
  if (!New->can(__WASI_RIGHTS_PATH_RENAME_TARGET)) {
241
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
242
0
  }
243
0
  EXPECTED_TRY(auto OldBuffer, resolvePath(Old, OldPath, false));
244
0
  EXPECTED_TRY(auto NewBuffer, resolvePath(New, NewPath, false));
245
246
0
  return INode::pathRename(Old->Node, std::string(OldPath), New->Node,
247
0
                           std::string(NewPath));
248
0
}
249
250
WasiExpect<void> VINode::pathSymlink(std::string_view OldPath,
251
                                     std::shared_ptr<VINode> New,
252
0
                                     std::string_view NewPath) {
253
0
  if (unlikely(!New)) {
254
0
    return WasiUnexpect(__WASI_ERRNO_BADF);
255
0
  }
256
0
  if (!New->can(__WASI_RIGHTS_PATH_SYMLINK)) {
257
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
258
0
  }
259
  // Resolve the new path without following its trailing component (an existing
260
  // link must not be followed, so creating over it fails with EEXIST), and
261
  // capture the link directory's depth below the fd.
262
0
  uint32_t ParentDepth = 0;
263
0
  EXPECTED_TRY(auto NewBuffer,
264
0
               resolvePath(New, NewPath, static_cast<__wasi_lookupflags_t>(0),
265
0
                           static_cast<VFS::Flags>(0), 0, true, &ParentDepth));
266
267
  // Reject relative targets that resolve outside the preopen root; store
268
  // in-bounds targets as-is.
269
0
  if (isSymlinkTargetEscaping(OldPath, ParentDepth)) {
270
0
    return WasiUnexpect(__WASI_ERRNO_PERM);
271
0
  }
272
0
  return New->Node.pathSymlink(std::string(OldPath), std::string(NewPath));
273
0
}
274
275
WasiExpect<void> VINode::pathUnlinkFile(std::shared_ptr<VINode> Fd,
276
0
                                        std::string_view Path) {
277
0
  if (!Fd->can(__WASI_RIGHTS_PATH_UNLINK_FILE)) {
278
0
    return WasiUnexpect(__WASI_ERRNO_NOTCAPABLE);
279
0
  }
280
0
  EXPECTED_TRY(auto Buffer,
281
0
               resolvePath(Fd, Path, static_cast<__wasi_lookupflags_t>(0)));
282
283
0
  return Fd->Node.pathUnlinkFile(std::string(Path));
284
0
}
285
286
WasiExpect<void>
287
VINode::getAddrinfo(std::string_view Node, std::string_view Service,
288
                    const __wasi_addrinfo_t &Hint, uint32_t MaxResLength,
289
                    Span<__wasi_addrinfo_t *> WasiAddrinfoArray,
290
                    Span<__wasi_sockaddr_t *> WasiSockaddrArray,
291
                    Span<char *> AiAddrSaDataArray,
292
                    Span<char *> AiCanonnameArray,
293
0
                    /*Out*/ __wasi_size_t &ResLength) noexcept {
294
0
  return INode::getAddrinfo(Node, Service, Hint, MaxResLength,
295
0
                            WasiAddrinfoArray, WasiSockaddrArray,
296
0
                            AiAddrSaDataArray, AiCanonnameArray, ResLength);
297
0
}
298
299
WasiExpect<std::shared_ptr<VINode>>
300
VINode::sockOpen(__wasi_address_family_t SysDomain,
301
0
                 __wasi_sock_type_t SockType) {
302
0
  EXPECTED_TRY(auto Node, INode::sockOpen(SysDomain, SockType));
303
0
  __wasi_rights_t Rights =
304
0
      __WASI_RIGHTS_SOCK_OPEN | __WASI_RIGHTS_SOCK_CLOSE |
305
0
      __WASI_RIGHTS_SOCK_RECV | __WASI_RIGHTS_SOCK_RECV_FROM |
306
0
      __WASI_RIGHTS_SOCK_SEND | __WASI_RIGHTS_SOCK_SEND_TO |
307
0
      __WASI_RIGHTS_SOCK_SHUTDOWN | __WASI_RIGHTS_SOCK_BIND |
308
0
      __WASI_RIGHTS_POLL_FD_READWRITE | __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS |
309
0
      __WASI_RIGHTS_FD_READ | __WASI_RIGHTS_FD_WRITE;
310
0
  return std::make_shared<VINode>(std::move(Node), Rights, Rights);
311
0
}
312
313
WasiExpect<std::shared_ptr<VINode>>
314
0
VINode::sockAccept(__wasi_fdflags_t FdFlags) {
315
0
  EXPECTED_TRY(auto NewNode, Node.sockAccept(FdFlags));
316
0
  __wasi_rights_t Rights =
317
0
      __WASI_RIGHTS_SOCK_RECV | __WASI_RIGHTS_SOCK_RECV_FROM |
318
0
      __WASI_RIGHTS_SOCK_SEND | __WASI_RIGHTS_SOCK_SEND_TO |
319
0
      __WASI_RIGHTS_SOCK_SHUTDOWN | __WASI_RIGHTS_POLL_FD_READWRITE |
320
0
      __WASI_RIGHTS_FD_FDSTAT_SET_FLAGS | __WASI_RIGHTS_FD_READ |
321
0
      __WASI_RIGHTS_FD_WRITE;
322
0
  return std::make_shared<VINode>(std::move(NewNode), Rights, Rights,
323
0
                                  std::string());
324
0
}
325
326
WasiExpect<std::shared_ptr<VINode>>
327
VINode::directOpen(std::string_view Path, __wasi_oflags_t OpenFlags,
328
                   __wasi_fdflags_t FdFlags, VFS::Flags VFSFlags,
329
                   __wasi_rights_t RightsBase,
330
0
                   __wasi_rights_t RightsInheriting) {
331
0
  std::string PathStr(Path);
332
333
0
  EXPECTED_TRY(auto NewNode,
334
0
               Node.pathOpen(std::move(PathStr), OpenFlags, FdFlags, VFSFlags));
335
0
  return std::make_shared<VINode>(std::move(NewNode), RightsBase,
336
0
                                  RightsInheriting);
337
0
}
338
339
WasiExpect<std::vector<char>>
340
VINode::resolvePath(std::shared_ptr<VINode> &Fd, std::string_view &Path,
341
                    __wasi_lookupflags_t LookupFlags, VFS::Flags VFSFlags,
342
                    uint8_t LinkCount, bool FollowTrailingSlashes,
343
0
                    uint32_t *ResolvedDepth) {
344
0
  std::vector<std::shared_ptr<VINode>> PartFds;
345
0
  std::vector<char> Buffer;
346
0
  do {
347
    // check empty path
348
0
    if (Path.empty() && (VFSFlags & VFS::AllowEmpty) == 0) {
349
0
      return WasiUnexpect(__WASI_ERRNO_NOENT);
350
0
    }
351
352
    // check absolute path
353
0
    if (!Path.empty() && Path[0] == '/') {
354
0
      return WasiUnexpect(__WASI_ERRNO_PERM);
355
0
    }
356
357
0
    if (!Fd) {
358
0
      return WasiUnexpect(__WASI_ERRNO_BADF);
359
0
    }
360
361
0
    if (!Fd->isDirectory()) {
362
0
      return WasiUnexpect(__WASI_ERRNO_NOTDIR);
363
0
    }
364
365
0
    if (!Fd->canBrowse()) {
366
0
      return WasiUnexpect(__WASI_ERRNO_ACCES);
367
0
    }
368
369
0
    do {
370
      // check self type
371
0
      auto Slash = Path.find('/');
372
0
      const auto Part = Path.substr(0, Slash);
373
0
      auto Remain = Path.substr(Part.size());
374
0
      while (!Remain.empty() && Remain[0] == '/') {
375
0
        Remain = Remain.substr(1);
376
0
      }
377
0
      const bool LastPart = Remain.empty() && (!FollowTrailingSlashes ||
378
0
                                               Slash == std::string_view::npos);
379
380
0
      if (!Part.empty() && Part[0] == '.') {
381
0
        if (Part.size() == 1) {
382
0
          if (LastPart) {
383
0
            if (ResolvedDepth) {
384
0
              *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
385
0
            }
386
0
            return Buffer;
387
0
          }
388
0
          Path = Remain;
389
0
          continue;
390
0
        }
391
0
        if (Part.size() == 2 && Part[1] == '.') {
392
0
          if (PartFds.empty()) {
393
0
            return WasiUnexpect(__WASI_ERRNO_PERM);
394
0
          }
395
0
          Fd = std::move(PartFds.back());
396
0
          PartFds.pop_back();
397
0
          Path = Remain;
398
0
          if (LastPart) {
399
0
            Path = "."sv;
400
0
            if (ResolvedDepth) {
401
0
              *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
402
0
            }
403
0
            return Buffer;
404
0
          }
405
0
          continue;
406
0
        }
407
0
      }
408
409
0
      if (LastPart && !(LookupFlags & __WASI_LOOKUPFLAGS_SYMLINK_FOLLOW)) {
410
0
        Path = Part;
411
0
        if (ResolvedDepth) {
412
0
          *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
413
0
        }
414
0
        return Buffer;
415
0
      }
416
417
0
      __wasi_filestat_t Filestat{};
418
0
      if (auto Res = Fd->Node.pathFilestatGet(std::string(Part), Filestat);
419
0
          unlikely(!Res)) {
420
0
        if (LastPart) {
421
0
          Path = Part;
422
0
          if (ResolvedDepth) {
423
0
            *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
424
0
          }
425
0
          return Buffer;
426
0
        }
427
0
        return WasiUnexpect(Res);
428
0
      }
429
430
0
      if (Filestat.filetype == __WASI_FILETYPE_SYMBOLIC_LINK) {
431
0
        if (++LinkCount >= kMaxNestedLinks) {
432
0
          return WasiUnexpect(__WASI_ERRNO_LOOP);
433
0
        }
434
435
0
        std::vector<char> NewBuffer(16384);
436
0
        __wasi_size_t NRead;
437
0
        EXPECTED_TRY(
438
0
            Fd->Node.pathReadlink(std::string(Part), NewBuffer, NRead));
439
0
        NewBuffer.resize(NRead);
440
        // Don't drop Buffer now because Path may referencing it.
441
0
        if (!Remain.empty()) {
442
0
          if (NewBuffer.back() != '/') {
443
0
            NewBuffer.push_back('/');
444
0
          }
445
0
          NewBuffer.insert(NewBuffer.end(), Remain.begin(), Remain.end());
446
0
        }
447
        // slow retry
448
0
        Buffer = std::move(NewBuffer);
449
0
        Path = std::string_view(Buffer.data(), Buffer.size());
450
0
        break;
451
0
      }
452
453
0
      if (LastPart) {
454
0
        Path = Part;
455
0
        if (ResolvedDepth) {
456
0
          *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
457
0
        }
458
0
        return Buffer;
459
0
      }
460
461
0
      if (Filestat.filetype != __WASI_FILETYPE_DIRECTORY) {
462
0
        return WasiUnexpect(__WASI_ERRNO_NOTDIR);
463
0
      }
464
465
0
      EXPECTED_TRY(auto Child, Fd->Node.pathOpen(
466
0
                                   std::string(Part), __WASI_OFLAGS_DIRECTORY,
467
0
                                   static_cast<__wasi_fdflags_t>(0), VFSFlags));
468
      // fast retry
469
0
      PartFds.push_back(std::exchange(
470
0
          Fd, std::make_shared<VINode>(std::move(Child), Fd->FsRightsBase,
471
0
                                       Fd->FsRightsInheriting)));
472
0
      Path = Remain;
473
0
      if (Path.empty()) {
474
0
        Path = "."sv;
475
0
        if (ResolvedDepth) {
476
0
          *ResolvedDepth = static_cast<uint32_t>(PartFds.size());
477
0
        }
478
0
        return {};
479
0
      }
480
0
      continue;
481
0
    } while (true);
482
0
  } while (true);
483
0
}
484
485
} // namespace WASI
486
} // namespace Host
487
} // namespace WasmEdge