Coverage Report

Created: 2026-09-28 06:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/WasmEdge/lib/host/wasi/inode-linux.cpp
Line
Count
Source
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright The WasmEdge Authors
3
4
#include "common/defines.h"
5
#include "common/types.h"
6
#if WASMEDGE_OS_LINUX
7
8
#include "common/errcode.h"
9
#include "common/variant.h"
10
#include "host/wasi/environ.h"
11
#include "host/wasi/inode.h"
12
#include "host/wasi/vfs.h"
13
#include "linux.h"
14
#include <algorithm>
15
#include <array>
16
#include <cstddef>
17
#include <cstdint>
18
#include <cstring>
19
#include <memory>
20
#include <new>
21
#include <string>
22
#include <string_view>
23
#include <vector>
24
25
using namespace std::literals;
26
27
namespace WasmEdge {
28
namespace Host {
29
namespace WASI {
30
31
namespace {
32
33
0
inline constexpr bool isSpecialFd(int Fd) noexcept {
34
0
  switch (Fd) {
35
0
  case STDIN_FILENO:
36
0
  case STDOUT_FILENO:
37
0
  case STDERR_FILENO:
38
0
    return true;
39
0
  default:
40
0
    return false;
41
0
  }
42
0
}
43
44
constexpr int openFlags(__wasi_oflags_t OpenFlags, __wasi_fdflags_t FdFlags,
45
0
                        VFS::Flags VFSFlags) noexcept {
46
0
  int Flags = O_NOFOLLOW;
47
0
#ifdef O_CLOEXEC
48
0
  Flags |= O_CLOEXEC;
49
0
#endif
50
51
0
  if (VFSFlags & VFS::Read) {
52
0
    if (VFSFlags & VFS::Write) {
53
0
      Flags |= O_RDWR;
54
0
    } else {
55
0
      Flags |= O_RDONLY;
56
0
    }
57
0
  } else if (VFSFlags & VFS::Write) {
58
0
    Flags |= O_WRONLY;
59
0
  } else {
60
0
#ifdef O_PATH
61
0
    if (OpenFlags == __WASI_OFLAGS_DIRECTORY) {
62
0
      Flags |= O_PATH;
63
0
    } else {
64
0
      Flags |= O_RDONLY;
65
0
    }
66
#else
67
    Flags |= O_RDONLY;
68
#endif
69
0
  }
70
71
0
  if (OpenFlags & __WASI_OFLAGS_CREAT) {
72
0
    Flags |= O_CREAT;
73
0
  }
74
0
  if (OpenFlags & __WASI_OFLAGS_DIRECTORY) {
75
0
    Flags |= O_DIRECTORY;
76
0
  }
77
0
  if (OpenFlags & __WASI_OFLAGS_EXCL) {
78
0
    Flags |= O_EXCL;
79
0
  }
80
0
  if ((OpenFlags & __WASI_OFLAGS_TRUNC) && (VFSFlags & VFS::Write)) {
81
0
    Flags |= O_TRUNC;
82
0
  }
83
84
  // Convert file descriptor flags.
85
0
  if ((FdFlags & __WASI_FDFLAGS_APPEND) != 0) {
86
0
    Flags |= O_APPEND;
87
0
  }
88
0
  if ((FdFlags & __WASI_FDFLAGS_DSYNC) != 0) {
89
0
#ifdef O_DSYNC
90
0
    Flags |= O_DSYNC;
91
#else
92
    Flags |= O_SYNC;
93
#endif
94
0
  }
95
0
  if ((FdFlags & __WASI_FDFLAGS_NONBLOCK) != 0) {
96
0
    Flags |= O_NONBLOCK;
97
0
  }
98
0
  if ((FdFlags & __WASI_FDFLAGS_RSYNC) != 0) {
99
0
#ifdef O_RSYNC
100
0
    Flags |= O_RSYNC;
101
#else
102
    Flags |= O_SYNC;
103
#endif
104
0
  }
105
0
  if ((FdFlags & __WASI_FDFLAGS_SYNC) != 0) {
106
0
    Flags |= O_SYNC;
107
0
  }
108
109
0
  return Flags;
110
0
}
111
112
std::pair<const char *, std::unique_ptr<char[]>>
113
0
createNullTerminatedString(std::string_view View) noexcept {
114
0
  const char *CStr = nullptr;
115
0
  std::unique_ptr<char[]> Buffer;
116
0
  if (!View.empty()) {
117
0
    if (const auto Pos = View.find_first_of('\0');
118
0
        Pos != std::string_view::npos) {
119
0
      CStr = View.data();
120
0
    } else {
121
0
      Buffer = std::make_unique<char[]>(View.size() + 1);
122
0
      std::copy(View.begin(), View.end(), Buffer.get());
123
0
      CStr = Buffer.get();
124
0
    }
125
0
  }
126
0
  return {CStr, std::move(Buffer)};
127
0
}
128
129
} // namespace
130
131
0
void FdHolder::reset() noexcept {
132
0
  if (likely(ok())) {
133
0
    if (likely(!isSpecialFd(Fd))) {
134
0
      ::close(Fd);
135
0
    }
136
0
    Fd = -1;
137
0
  }
138
0
}
139
140
0
void TimerHolder::reset() noexcept {
141
0
  if (likely(Id.has_value())) {
142
0
    timer_delete(*Id);
143
0
    Id.reset();
144
0
  }
145
0
}
146
147
0
void DirHolder::reset() noexcept {
148
0
  if (likely(Dir != nullptr)) {
149
0
    closedir(Dir);
150
0
    Dir = nullptr;
151
0
    Cookie = 0;
152
0
  }
153
0
}
154
155
namespace {
156
0
WasiExpect<INode> createStdNode(int32_t Fd) {
157
0
  if (Fd < 0) {
158
0
    spdlog::error("    Invalid file descriptor: {}"sv, Fd);
159
0
    return WasiUnexpect(__WASI_ERRNO_BADF);
160
0
  }
161
162
0
  if (fcntl(Fd, F_GETFD) == -1) {
163
0
    spdlog::error("    Invalid file descriptor: {}"sv, Fd);
164
0
    return WasiUnexpect(__WASI_ERRNO_BADF);
165
0
  }
166
167
0
  return INode(Fd, false);
168
0
}
169
} // namespace
170
171
0
INode INode::stdIn() noexcept { return INode(STDIN_FILENO); }
172
173
0
INode INode::stdOut() noexcept { return INode(STDOUT_FILENO); }
174
175
0
INode INode::stdErr() noexcept { return INode(STDERR_FILENO); }
176
177
0
WasiExpect<INode> INode::fromFd(int32_t FdNum) { return createStdNode(FdNum); }
178
179
WasiExpect<INode> INode::open(std::string Path, __wasi_oflags_t OpenFlags,
180
                              __wasi_fdflags_t FdFlags,
181
0
                              VFS::Flags VFSFlags) noexcept {
182
0
  const int Flags = openFlags(OpenFlags, FdFlags, VFSFlags);
183
184
0
  if (auto NewFd = ::open(Path.c_str(), Flags, 0644); unlikely(NewFd < 0)) {
185
0
    return WasiUnexpect(fromErrNo(errno));
186
0
  } else {
187
0
    INode New(NewFd);
188
189
#ifndef O_CLOEXEC
190
    if (auto Res = ::fcntl(New.Fd, F_SETFD, FD_CLOEXEC); unlikely(Res != 0)) {
191
      return WasiUnexpect(fromErrNo(errno));
192
    }
193
#endif
194
0
    return New;
195
0
  }
196
0
}
197
198
WasiExpect<void> INode::fdAdvise(__wasi_filesize_t Offset,
199
                                 __wasi_filesize_t Len,
200
0
                                 __wasi_advice_t Advice) const noexcept {
201
0
  if (auto Res = ::posix_fadvise(Fd, Offset, Len, toAdvice(Advice));
202
0
      unlikely(Res != 0)) {
203
0
    return WasiUnexpect(fromErrNo(errno));
204
0
  }
205
206
0
  return {};
207
0
}
208
209
WasiExpect<void> INode::fdAllocate(__wasi_filesize_t Offset,
210
0
                                   __wasi_filesize_t Len) const noexcept {
211
0
  if (auto Res = ::posix_fallocate(Fd, Offset, Len); unlikely(Res != 0)) {
212
    // https://man7.org/linux/man-pages/man3/posix_fallocate.3.html
213
    // posix_fallocate will not set errno, so use the return value directly.
214
0
    return WasiUnexpect(fromErrNo(Res));
215
0
  }
216
217
0
  return {};
218
0
}
219
220
0
WasiExpect<void> INode::fdDatasync() const noexcept {
221
0
  if (auto Res = ::fdatasync(Fd); unlikely(Res != 0)) {
222
0
    return WasiUnexpect(fromErrNo(errno));
223
0
  }
224
225
0
  return {};
226
0
}
227
228
0
WasiExpect<void> INode::fdFdstatGet(__wasi_fdstat_t &FdStat) const noexcept {
229
0
  EXPECTED_TRY(updateStat());
230
231
0
  if (int FdFlags = ::fcntl(Fd, F_GETFL); unlikely(FdFlags < 0)) {
232
0
    return WasiUnexpect(fromErrNo(errno));
233
0
  } else {
234
0
    FdStat.fs_filetype = EndianValue(unsafeFiletype()).le();
235
236
0
    FdStat.fs_flags = static_cast<__wasi_fdflags_t>(0);
237
0
    if (FdFlags & O_APPEND) {
238
0
      FdStat.fs_flags |= __WASI_FDFLAGS_APPEND;
239
0
    }
240
0
    if (FdFlags & O_DSYNC) {
241
0
      FdStat.fs_flags |= __WASI_FDFLAGS_DSYNC;
242
0
    }
243
0
    if (FdFlags & O_NONBLOCK) {
244
0
      FdStat.fs_flags |= __WASI_FDFLAGS_NONBLOCK;
245
0
    }
246
0
    if (FdFlags & O_SYNC) {
247
0
      FdStat.fs_flags |= __WASI_FDFLAGS_RSYNC | __WASI_FDFLAGS_SYNC;
248
0
    }
249
0
  }
250
0
  FdStat.fs_flags = EndianValue(FdStat.fs_flags).le();
251
252
0
  return {};
253
0
}
254
255
WasiExpect<void>
256
0
INode::fdFdstatSetFlags(__wasi_fdflags_t FdFlags) const noexcept {
257
0
  int SysFlag = 0;
258
0
  if (FdFlags & __WASI_FDFLAGS_NONBLOCK) {
259
0
    SysFlag |= O_NONBLOCK;
260
0
  }
261
0
  if (FdFlags & __WASI_FDFLAGS_APPEND) {
262
0
    SysFlag |= O_APPEND;
263
0
  }
264
0
  if (FdFlags & __WASI_FDFLAGS_DSYNC) {
265
0
    SysFlag |= O_DSYNC;
266
0
  }
267
0
  if (FdFlags & __WASI_FDFLAGS_RSYNC) {
268
0
    SysFlag |= O_RSYNC;
269
0
  }
270
0
  if (FdFlags & __WASI_FDFLAGS_SYNC) {
271
0
    SysFlag |= O_SYNC;
272
0
  }
273
274
0
  if (auto Res = ::fcntl(Fd, F_SETFL, SysFlag); unlikely(Res != 0)) {
275
0
    return WasiUnexpect(fromErrNo(errno));
276
0
  }
277
278
0
  return {};
279
0
}
280
281
WasiExpect<void>
282
0
INode::fdFilestatGet(__wasi_filestat_t &Filestat) const noexcept {
283
0
  EXPECTED_TRY(updateStat());
284
285
  // Zeroing out these values to prevent leaking information about the host
286
  // environment from special fd such as stdin, stdout and stderr.
287
0
  Filestat.dev = isSpecialFd(Fd) ? 0 : EndianValue(Stat->st_dev).le();
288
0
  Filestat.ino = isSpecialFd(Fd) ? 0 : EndianValue(Stat->st_ino).le();
289
0
  Filestat.filetype = EndianValue(unsafeFiletype()).le();
290
0
  Filestat.nlink = isSpecialFd(Fd) ? 0 : EndianValue(Stat->st_nlink).le();
291
0
  Filestat.size = isSpecialFd(Fd) ? 0 : EndianValue(Stat->st_size).le();
292
0
  Filestat.atim = isSpecialFd(Fd) ? 0 : fromTimespec(Stat->st_atim).le();
293
0
  Filestat.mtim = isSpecialFd(Fd) ? 0 : fromTimespec(Stat->st_mtim).le();
294
0
  Filestat.ctim = isSpecialFd(Fd) ? 0 : fromTimespec(Stat->st_ctim).le();
295
296
0
  return {};
297
0
}
298
299
WasiExpect<void>
300
0
INode::fdFilestatSetSize(__wasi_filesize_t Size) const noexcept {
301
0
  if (auto Res = ::ftruncate(Fd, Size); unlikely(Res == -1)) {
302
0
    return WasiUnexpect(fromErrNo(errno));
303
0
  }
304
305
0
  return {};
306
0
}
307
308
WasiExpect<void>
309
INode::fdFilestatSetTimes(__wasi_timestamp_t ATim, __wasi_timestamp_t MTim,
310
0
                          __wasi_fstflags_t FstFlags) const noexcept {
311
0
#if __GLIBC_PREREQ(2, 6) || __BIONIC__
312
0
  timespec SysTimespec[2];
313
0
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
314
0
    SysTimespec[0] = toTimespec(ATim);
315
0
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
316
0
    SysTimespec[0].tv_nsec = UTIME_NOW;
317
0
  } else {
318
0
    SysTimespec[0].tv_nsec = UTIME_OMIT;
319
0
  }
320
0
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
321
0
    SysTimespec[1] = toTimespec(MTim);
322
0
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
323
0
    SysTimespec[1].tv_nsec = UTIME_NOW;
324
0
  } else {
325
0
    SysTimespec[1].tv_nsec = UTIME_OMIT;
326
0
  }
327
328
0
  if (auto Res = ::futimens(Fd, SysTimespec); unlikely(Res != 0)) {
329
0
    return WasiUnexpect(fromErrNo(errno));
330
0
  }
331
#else
332
  bool NeedNow = false;
333
  bool NeedFile = false;
334
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
335
    // Nothing to do.
336
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
337
    NeedNow = true;
338
  } else {
339
    NeedFile = true;
340
  }
341
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
342
    // Nothing to do.
343
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
344
    NeedNow = true;
345
  } else {
346
    NeedFile = true;
347
  }
348
349
  if (NeedFile) {
350
    EXPECTED_TRY(updateStat());
351
  }
352
353
  timespec Now;
354
  if (NeedNow) {
355
    if (auto Res = ::clock_gettime(CLOCK_REALTIME, &Now); unlikely(Res != 0)) {
356
      return WasiUnexpect(fromErrNo(errno));
357
    }
358
  }
359
360
  timeval SysTimeval[2];
361
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
362
    SysTimeval[0] = toTimeval(ATim);
363
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
364
    SysTimeval[0] = toTimeval(Now);
365
  } else {
366
    SysTimeval[0] = toTimeval(Stat->st_atim);
367
  }
368
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
369
    SysTimeval[1] = toTimeval(MTim);
370
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
371
    SysTimeval[1] = toTimeval(Now);
372
  } else {
373
    SysTimeval[1] = toTimeval(Stat->st_mtim);
374
  }
375
376
  if (auto Res = ::futimes(Fd, SysTimeval); unlikely(Res != 0)) {
377
    return WasiUnexpect(fromErrNo(errno));
378
  }
379
#endif
380
381
0
  return {};
382
0
}
383
384
WasiExpect<void> INode::fdPread(Span<Span<uint8_t>> IOVs,
385
                                __wasi_filesize_t Offset,
386
0
                                __wasi_size_t &NRead) const noexcept {
387
0
  iovec SysIOVs[kIOVMax];
388
0
  size_t SysIOVsSize = 0;
389
0
  for (auto &IOV : IOVs) {
390
0
    SysIOVs[SysIOVsSize].iov_base = IOV.data();
391
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
392
0
    ++SysIOVsSize;
393
0
  }
394
395
0
#if __GLIBC_PREREQ(2, 10)
396
  // Store read bytes length.
397
0
  if (auto Res = ::preadv(Fd, SysIOVs, SysIOVsSize, Offset);
398
0
      unlikely(Res < 0)) {
399
0
    return WasiUnexpect(fromErrNo(errno));
400
0
  } else {
401
0
    NRead = EndianValue(static_cast<__wasi_size_t>(Res)).le();
402
0
  }
403
#else
404
  const auto OldOffset = ::lseek(Fd, 0, SEEK_CUR);
405
  if (OldOffset < 0) {
406
    return WasiUnexpect(fromErrNo(errno));
407
  }
408
  if (::lseek(Fd, Offset, SEEK_SET) < 0 ||
409
      ::lseek(Fd, OldOffset, SEEK_SET) < 0) {
410
    return WasiUnexpect(fromErrNo(errno));
411
  }
412
  if (auto Res = ::readv(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) {
413
    ::lseek(Fd, OldOffset, SEEK_SET);
414
    return WasiUnexpect(fromErrNo(errno));
415
  } else {
416
    if (::lseek(Fd, OldOffset, SEEK_SET) < 0) {
417
      return WasiUnexpect(fromErrNo(errno));
418
    }
419
    NRead = EndianValue(static_cast<__wasi_size_t>(Res)).le();
420
  }
421
#endif
422
423
0
  return {};
424
0
}
425
426
WasiExpect<void> INode::fdPwrite(Span<Span<const uint8_t>> IOVs,
427
                                 __wasi_filesize_t Offset,
428
0
                                 __wasi_size_t &NWritten) const noexcept {
429
0
  iovec SysIOVs[kIOVMax];
430
0
  size_t SysIOVsSize = 0;
431
0
  for (auto &IOV : IOVs) {
432
0
    SysIOVs[SysIOVsSize].iov_base = const_cast<uint8_t *>(IOV.data());
433
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
434
0
    ++SysIOVsSize;
435
0
  }
436
437
0
#if __GLIBC_PREREQ(2, 10)
438
0
  if (auto Res = ::pwritev(Fd, SysIOVs, SysIOVsSize, Offset);
439
0
      unlikely(Res < 0)) {
440
0
    return WasiUnexpect(fromErrNo(errno));
441
0
  } else {
442
0
    NWritten = EndianValue(static_cast<__wasi_size_t>(Res)).le();
443
0
  }
444
#else
445
  const auto OldOffset = ::lseek(Fd, 0, SEEK_CUR);
446
  if (OldOffset < 0) {
447
    return WasiUnexpect(fromErrNo(errno));
448
  }
449
  if (::lseek(Fd, Offset, SEEK_SET) < 0 ||
450
      ::lseek(Fd, OldOffset, SEEK_SET) < 0) {
451
    return WasiUnexpect(fromErrNo(errno));
452
  }
453
  if (auto Res = ::writev(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) {
454
    ::lseek(Fd, OldOffset, SEEK_SET);
455
    return WasiUnexpect(fromErrNo(errno));
456
  } else {
457
    if (::lseek(Fd, OldOffset, SEEK_SET) < 0) {
458
      return WasiUnexpect(fromErrNo(errno));
459
    }
460
    NWritten = EndianValue(static_cast<__wasi_size_t>(Res)).le();
461
  }
462
#endif
463
464
0
  return {};
465
0
}
466
467
WasiExpect<void> INode::fdRead(Span<Span<uint8_t>> IOVs,
468
0
                               __wasi_size_t &NRead) const noexcept {
469
0
  iovec SysIOVs[kIOVMax];
470
0
  size_t SysIOVsSize = 0;
471
0
  for (auto &IOV : IOVs) {
472
0
    SysIOVs[SysIOVsSize].iov_base = IOV.data();
473
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
474
0
    ++SysIOVsSize;
475
0
  }
476
477
0
  if (auto Res = ::readv(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) {
478
0
    return WasiUnexpect(fromErrNo(errno));
479
0
  } else {
480
0
    NRead = EndianValue(static_cast<__wasi_size_t>(Res)).le();
481
0
  }
482
483
0
  return {};
484
0
}
485
486
// Due to the unfortunate design of wasi::fd_readdir, It's nearly impossible to
487
// provide a correct implementation. The below implementation is just a
488
// workaround for most usages and may not be correct in some edge cases. The
489
// readdir entry API is going to be updated to use a stream type, so we don't
490
// have to deal with it right now.
491
WasiExpect<void> INode::fdReaddir(Span<uint8_t> Buffer,
492
                                  __wasi_dircookie_t Cookie,
493
0
                                  __wasi_size_t &Size) noexcept {
494
0
  if (unlikely(!Dir.ok())) {
495
0
    if (FdHolder NewFd(::dup(Fd)); unlikely(!NewFd.ok())) {
496
0
      return WasiUnexpect(fromErrNo(errno));
497
0
    } else if (DIR *D = ::fdopendir(NewFd.Fd); unlikely(!D)) {
498
0
      return WasiUnexpect(fromErrNo(errno));
499
0
    } else {
500
0
      NewFd.release();
501
0
      Dir.emplace(D);
502
0
    }
503
0
  }
504
505
0
  if (Cookie == 0) {
506
0
    ::rewinddir(Dir.Dir);
507
0
  } else if (unlikely(Cookie != Dir.Cookie)) {
508
0
    ::seekdir(Dir.Dir, Cookie);
509
0
  }
510
511
0
  Size = 0;
512
0
  do {
513
0
    if (!Dir.Buffer.empty()) {
514
0
      const auto NewDataSize =
515
0
          std::min<uint32_t>(Buffer.size(), Dir.Buffer.size());
516
0
      std::copy(Dir.Buffer.begin(), Dir.Buffer.begin() + NewDataSize,
517
0
                Buffer.begin());
518
0
      Buffer = Buffer.subspan(NewDataSize);
519
0
      Size += NewDataSize;
520
0
      Dir.Buffer.clear();
521
0
      if (unlikely(Buffer.empty())) {
522
0
        break;
523
0
      }
524
0
    }
525
0
    errno = 0;
526
0
    dirent *SysDirent = ::readdir(Dir.Dir);
527
0
    if (SysDirent == nullptr) {
528
0
      if (errno != 0) {
529
0
        return WasiUnexpect(fromErrNo(errno));
530
0
      }
531
      // End of entries
532
0
      break;
533
0
    }
534
0
    Dir.Cookie = SysDirent->d_off;
535
0
    std::string_view Name = SysDirent->d_name;
536
537
0
    Dir.Buffer.resize(sizeof(__wasi_dirent_t) + Name.size());
538
539
0
    __wasi_dirent_t *const Dirent =
540
0
        reinterpret_cast<__wasi_dirent_t *>(Dir.Buffer.data());
541
0
    Dirent->d_next = Dir.Cookie;
542
0
    Dirent->d_ino = SysDirent->d_ino;
543
0
    Dirent->d_type = fromFileType(SysDirent->d_type);
544
0
    Dirent->d_namlen = Name.size();
545
0
    std::copy(Name.cbegin(), Name.cend(),
546
0
              Dir.Buffer.begin() + sizeof(__wasi_dirent_t));
547
0
  } while (!Buffer.empty());
548
0
  Size = EndianValue(Size).le();
549
0
  return {};
550
0
}
551
552
WasiExpect<void> INode::fdSeek(__wasi_filedelta_t Offset,
553
                               __wasi_whence_t Whence,
554
0
                               __wasi_filesize_t &Size) const noexcept {
555
0
  if (auto Res = ::lseek(Fd, Offset, toWhence(Whence)); unlikely(Res < 0)) {
556
0
    return WasiUnexpect(fromErrNo(errno));
557
0
  } else {
558
0
    Size = EndianValue(static_cast<__wasi_filesize_t>(Res)).le();
559
0
  }
560
561
0
  return {};
562
0
}
563
564
0
WasiExpect<void> INode::fdSync() const noexcept {
565
0
  if (auto Res = ::fsync(Fd); unlikely(Res != 0)) {
566
0
    return WasiUnexpect(fromErrNo(errno));
567
0
  }
568
569
0
  return {};
570
0
}
571
572
0
WasiExpect<void> INode::fdTell(__wasi_filesize_t &Size) const noexcept {
573
0
  if (auto Res = ::lseek(Fd, 0, SEEK_CUR); unlikely(Res < 0)) {
574
0
    return WasiUnexpect(fromErrNo(errno));
575
0
  } else {
576
0
    Size = EndianValue(static_cast<__wasi_filesize_t>(Res)).le();
577
0
  }
578
579
0
  return {};
580
0
}
581
582
WasiExpect<void> INode::fdWrite(Span<Span<const uint8_t>> IOVs,
583
0
                                __wasi_size_t &NWritten) const noexcept {
584
0
  iovec SysIOVs[kIOVMax];
585
0
  size_t SysIOVsSize = 0;
586
0
  for (auto &IOV : IOVs) {
587
0
    SysIOVs[SysIOVsSize].iov_base = const_cast<uint8_t *>(IOV.data());
588
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
589
0
    ++SysIOVsSize;
590
0
  }
591
592
0
  if (auto Res = ::writev(Fd, SysIOVs, SysIOVsSize); unlikely(Res < 0)) {
593
0
    return WasiUnexpect(fromErrNo(errno));
594
0
  } else {
595
0
    NWritten = EndianValue(static_cast<__wasi_size_t>(Res)).le();
596
0
  }
597
598
0
  return {};
599
0
}
600
601
0
WasiExpect<uint64_t> INode::getNativeHandler() const noexcept {
602
0
  return static_cast<uint64_t>(Fd);
603
0
}
604
605
0
WasiExpect<void> INode::pathCreateDirectory(std::string Path) const noexcept {
606
0
  if (auto Res = ::mkdirat(Fd, Path.c_str(), 0755); unlikely(Res != 0)) {
607
0
    return WasiUnexpect(fromErrNo(errno));
608
0
  }
609
610
0
  return {};
611
0
}
612
613
WasiExpect<void>
614
INode::pathFilestatGet(std::string Path,
615
0
                       __wasi_filestat_t &Filestat) const noexcept {
616
0
  struct stat SysFStat;
617
0
  if (int Res = ::fstatat(Fd, Path.c_str(), &SysFStat, AT_SYMLINK_NOFOLLOW);
618
0
      unlikely(Res != 0)) {
619
0
    return WasiUnexpect(fromErrNo(errno));
620
0
  }
621
622
0
  Filestat.dev = EndianValue(SysFStat.st_dev).le();
623
0
  Filestat.ino = EndianValue(SysFStat.st_ino).le();
624
0
  Filestat.filetype = fromFileType(SysFStat.st_mode);
625
0
  Filestat.nlink = EndianValue(SysFStat.st_nlink).le();
626
0
  Filestat.size = EndianValue(SysFStat.st_size).le();
627
0
  Filestat.atim = fromTimespec(SysFStat.st_atim).le();
628
0
  Filestat.mtim = fromTimespec(SysFStat.st_mtim).le();
629
0
  Filestat.ctim = fromTimespec(SysFStat.st_ctim).le();
630
631
0
  return {};
632
0
}
633
634
WasiExpect<void>
635
INode::pathFilestatSetTimes(std::string Path, __wasi_timestamp_t ATim,
636
                            __wasi_timestamp_t MTim,
637
0
                            __wasi_fstflags_t FstFlags) const noexcept {
638
0
#if __GLIBC_PREREQ(2, 6) || __BIONIC__
639
0
  timespec SysTimespec[2];
640
0
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
641
0
    SysTimespec[0] = toTimespec(ATim);
642
0
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
643
0
    SysTimespec[0].tv_nsec = UTIME_NOW;
644
0
  } else {
645
0
    SysTimespec[0].tv_nsec = UTIME_OMIT;
646
0
  }
647
0
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
648
0
    SysTimespec[1] = toTimespec(MTim);
649
0
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
650
0
    SysTimespec[1].tv_nsec = UTIME_NOW;
651
0
  } else {
652
0
    SysTimespec[1].tv_nsec = UTIME_OMIT;
653
0
  }
654
655
0
  if (auto Res =
656
0
          ::utimensat(Fd, Path.c_str(), SysTimespec, AT_SYMLINK_NOFOLLOW);
657
0
      unlikely(Res != 0)) {
658
0
    return WasiUnexpect(fromErrNo(errno));
659
0
  }
660
#else
661
  bool NeedNow = false;
662
  bool NeedFile = false;
663
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
664
    // Nothing to do.
665
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
666
    NeedNow = true;
667
  } else {
668
    NeedFile = true;
669
  }
670
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
671
    // Nothing to do.
672
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
673
    NeedNow = true;
674
  } else {
675
    NeedFile = true;
676
  }
677
678
#ifdef O_PATH
679
  const int OFlags = O_PATH | O_SYMLINK;
680
#else
681
  const int OFlags = O_RDONLY | O_SYMLINK;
682
#endif
683
684
  FdHolder Target(::openat(Fd, Path.c_str(), OFlags));
685
  if (unlikely(!Target.ok())) {
686
    return WasiUnexpect(fromErrNo(errno));
687
  }
688
689
  struct stat SysStat;
690
  if (NeedFile) {
691
    if (auto Res = ::fstat(Target.Fd, &SysStat); unlikely(Res != 0)) {
692
      return WasiUnexpect(fromErrNo(errno));
693
    }
694
  }
695
696
  timespec Now;
697
  if (NeedNow) {
698
    if (auto Res = ::clock_gettime(CLOCK_REALTIME, &Now); unlikely(Res != 0)) {
699
      return WasiUnexpect(fromErrNo(errno));
700
    }
701
  }
702
703
  timeval SysTimeval[2];
704
  if (FstFlags & __WASI_FSTFLAGS_ATIM) {
705
    SysTimeval[0] = toTimeval(ATim);
706
  } else if (FstFlags & __WASI_FSTFLAGS_ATIM_NOW) {
707
    SysTimeval[0] = toTimeval(Now);
708
  } else {
709
    SysTimeval[0] = toTimeval(SysStat.st_atim);
710
  }
711
  if (FstFlags & __WASI_FSTFLAGS_MTIM) {
712
    SysTimeval[1] = toTimeval(MTim);
713
  } else if (FstFlags & __WASI_FSTFLAGS_MTIM_NOW) {
714
    SysTimeval[1] = toTimeval(Now);
715
  } else {
716
    SysTimeval[1] = toTimeval(SysStat.st_mtim);
717
  }
718
719
  if (auto Res = ::futimes(Target.Fd, SysTimeval); unlikely(Res != 0)) {
720
    return WasiUnexpect(fromErrNo(errno));
721
  }
722
#endif
723
724
0
  return {};
725
0
}
726
727
WasiExpect<void> INode::pathLink(const INode &Old, std::string OldPath,
728
                                 const INode &New,
729
0
                                 std::string NewPath) noexcept {
730
0
  if (auto Res = ::linkat(Old.Fd, OldPath.c_str(), New.Fd, NewPath.c_str(), 0);
731
0
      unlikely(Res != 0)) {
732
0
    return WasiUnexpect(fromErrNo(errno));
733
0
  }
734
735
0
  return {};
736
0
}
737
738
WasiExpect<INode> INode::pathOpen(std::string Path, __wasi_oflags_t OpenFlags,
739
                                  __wasi_fdflags_t FdFlags,
740
0
                                  VFS::Flags VFSFlags) const noexcept {
741
0
  const int Flags = openFlags(OpenFlags, FdFlags, VFSFlags);
742
743
0
  if (auto NewFd = ::openat(Fd, Path.c_str(), Flags, 0644);
744
0
      unlikely(NewFd < 0)) {
745
0
    return WasiUnexpect(fromErrNo(errno));
746
0
  } else {
747
0
    INode New(NewFd);
748
749
#ifndef O_CLOEXEC
750
    if (auto Res = ::fcntl(New.Fd, F_SETFD, FD_CLOEXEC); unlikely(Res != 0)) {
751
      return WasiUnexpect(fromErrNo(errno));
752
    }
753
#endif
754
0
    return New;
755
0
  }
756
0
}
757
758
WasiExpect<void> INode::pathReadlink(std::string Path, Span<char> Buffer,
759
0
                                     __wasi_size_t &NRead) const noexcept {
760
0
  if (auto Res = ::readlinkat(Fd, Path.c_str(), Buffer.data(), Buffer.size());
761
0
      unlikely(Res < 0)) {
762
0
    return WasiUnexpect(fromErrNo(errno));
763
0
  } else {
764
0
    NRead = EndianValue(static_cast<__wasi_size_t>(Res)).le();
765
0
  }
766
767
0
  return {};
768
0
}
769
770
0
WasiExpect<void> INode::pathRemoveDirectory(std::string Path) const noexcept {
771
0
  if (auto Res = ::unlinkat(Fd, Path.c_str(), AT_REMOVEDIR);
772
0
      unlikely(Res < 0)) {
773
0
    return WasiUnexpect(fromErrNo(errno));
774
0
  }
775
776
0
  return {};
777
0
}
778
779
WasiExpect<void> INode::pathRename(const INode &Old, std::string OldPath,
780
                                   const INode &New,
781
0
                                   std::string NewPath) noexcept {
782
0
  if (auto Res = ::renameat(Old.Fd, OldPath.c_str(), New.Fd, NewPath.c_str());
783
0
      unlikely(Res != 0)) {
784
0
    return WasiUnexpect(fromErrNo(errno));
785
0
  }
786
787
0
  return {};
788
0
}
789
790
WasiExpect<void> INode::pathSymlink(std::string OldPath,
791
0
                                    std::string NewPath) const noexcept {
792
0
  if (auto Res = ::symlinkat(OldPath.c_str(), Fd, NewPath.c_str());
793
0
      unlikely(Res != 0)) {
794
0
    return WasiUnexpect(fromErrNo(errno));
795
0
  }
796
797
0
  return {};
798
0
}
799
800
0
WasiExpect<void> INode::pathUnlinkFile(std::string Path) const noexcept {
801
0
  if (auto Res = ::unlinkat(Fd, Path.c_str(), 0); unlikely(Res < 0)) {
802
0
    return WasiUnexpect(fromErrNo(errno));
803
0
  }
804
805
0
  return {};
806
0
}
807
808
WasiExpect<void> INode::getAddrinfo(std::string_view Node,
809
                                    std::string_view Service,
810
                                    const __wasi_addrinfo_t &Hint,
811
                                    uint32_t MaxResLength,
812
                                    Span<__wasi_addrinfo_t *> WasiAddrinfoArray,
813
                                    Span<__wasi_sockaddr_t *> WasiSockaddrArray,
814
                                    Span<Span<char>> AiAddrSaDataArray,
815
                                    Span<Span<char>> AiCanonnameArray,
816
0
                                    /*Out*/ __wasi_size_t &ResLength) noexcept {
817
0
  const auto [NodeCStr, NodeBuf] = createNullTerminatedString(Node);
818
0
  const auto [ServiceCStr, ServiceBuf] = createNullTerminatedString(Service);
819
820
0
  struct addrinfo SysHint;
821
0
  SysHint.ai_flags = toAIFlags(Hint.ai_flags);
822
0
  SysHint.ai_family = toAddressFamily(Hint.ai_family);
823
0
  SysHint.ai_socktype = toSockType(Hint.ai_socktype);
824
0
  SysHint.ai_protocol = toProtocol(Hint.ai_protocol);
825
0
  SysHint.ai_addrlen = Hint.ai_addrlen;
826
0
  SysHint.ai_addr = nullptr;
827
0
  SysHint.ai_canonname = nullptr;
828
0
  SysHint.ai_next = nullptr;
829
830
0
  using AddrinfoPtr =
831
0
      std::unique_ptr<struct addrinfo, decltype(&::freeaddrinfo)>;
832
0
  struct addrinfo *Result = nullptr;
833
0
  const int Res = ::getaddrinfo(NodeCStr, ServiceCStr, &SysHint, &Result);
834
0
  if (unlikely(Res != 0)) {
835
0
    return WasiUnexpect(fromEAIErrNo(Res));
836
0
  }
837
0
  AddrinfoPtr SysResPtr(Result, &::freeaddrinfo);
838
839
0
  std::array<struct addrinfo *, kAddrinfoMax> Selected{};
840
0
  __wasi_size_t SelectedLength = 0;
841
0
  const __wasi_size_t SelectionLimit =
842
0
      std::min(MaxResLength, static_cast<__wasi_size_t>(Selected.size()));
843
0
  for (struct addrinfo *SysResItem = SysResPtr.get();
844
0
       SysResItem != nullptr && SelectedLength < SelectionLimit;
845
0
       SysResItem = SysResItem->ai_next) {
846
0
    if (SysResItem->ai_family != AF_INET && SysResItem->ai_family != AF_INET6) {
847
0
      continue;
848
0
    }
849
0
    if (SysResItem->ai_socktype != 0 && SysResItem->ai_socktype != SOCK_DGRAM &&
850
0
        SysResItem->ai_socktype != SOCK_STREAM) {
851
0
      continue;
852
0
    }
853
0
    if (SysResItem->ai_protocol != IPPROTO_IP &&
854
0
        SysResItem->ai_protocol != IPPROTO_TCP &&
855
0
        SysResItem->ai_protocol != IPPROTO_UDP) {
856
0
      continue;
857
0
    }
858
0
    Selected[SelectedLength++] = SysResItem;
859
0
  }
860
0
  if (WasiAddrinfoArray.size() < SelectedLength ||
861
0
      WasiSockaddrArray.size() < SelectedLength ||
862
0
      AiAddrSaDataArray.size() < SelectedLength ||
863
0
      AiCanonnameArray.size() < SelectedLength) {
864
0
    return WasiUnexpect(__WASI_ERRNO_FAULT);
865
0
  }
866
867
0
  for (uint32_t Idx = 0; Idx < SelectedLength; Idx++) {
868
0
    const auto *SysResItem = Selected[Idx];
869
0
    const size_t CanonnameSize =
870
0
        SysResItem->ai_canonname == nullptr
871
0
            ? 0
872
0
            : std::strlen(SysResItem->ai_canonname) + 1;
873
0
    if (CanonnameSize > AiCanonnameArray[Idx].size()) {
874
0
      return WasiUnexpect(__WASI_ERRNO_FAULT);
875
0
    }
876
0
    AiCanonnameArray[Idx] = AiCanonnameArray[Idx].first(CanonnameSize);
877
878
0
    if (SysResItem->ai_addr == nullptr ||
879
0
        SysResItem->ai_addrlen < offsetof(sockaddr, sa_data)) {
880
0
      return WasiUnexpect(__WASI_ERRNO_FAULT);
881
0
    }
882
0
    size_t SaSize;
883
0
    switch (SysResItem->ai_addr->sa_family) {
884
0
    case AF_INET:
885
0
      SaSize = sizeof(sockaddr_in) - offsetof(sockaddr_in, sin_port);
886
0
      if (SysResItem->ai_addrlen < sizeof(sockaddr_in)) {
887
0
        return WasiUnexpect(__WASI_ERRNO_FAULT);
888
0
      }
889
0
      break;
890
0
    case AF_INET6:
891
0
      SaSize = sizeof(sockaddr_in6) - offsetof(sockaddr_in6, sin6_port);
892
0
      if (SysResItem->ai_addrlen < sizeof(sockaddr_in6)) {
893
0
        return WasiUnexpect(__WASI_ERRNO_FAULT);
894
0
      }
895
0
      break;
896
0
    default:
897
0
      return WasiUnexpect(__WASI_ERRNO_FAULT);
898
0
    }
899
0
    if (SaSize > AiAddrSaDataArray[Idx].size()) {
900
0
      return WasiUnexpect(__WASI_ERRNO_FAULT);
901
0
    }
902
0
    AiAddrSaDataArray[Idx] = AiAddrSaDataArray[Idx].first(SaSize);
903
0
  }
904
905
0
  for (uint32_t Idx = 0; Idx < SelectedLength; Idx++) {
906
0
    const auto *SysResItem = Selected[Idx];
907
0
    auto &CurAddrinfo = WasiAddrinfoArray[Idx];
908
0
    CurAddrinfo->ai_flags = fromAIFlags(SysResItem->ai_flags);
909
0
    CurAddrinfo->ai_socktype = fromSockType(SysResItem->ai_socktype);
910
0
    CurAddrinfo->ai_protocol = fromProtocol(SysResItem->ai_protocol);
911
0
    CurAddrinfo->ai_family = fromAddressFamily(SysResItem->ai_family);
912
0
    CurAddrinfo->ai_addrlen = SysResItem->ai_addrlen;
913
914
    // process ai_canonname in addrinfo
915
0
    const auto &CurAiCanonname = AiCanonnameArray[Idx];
916
0
    CurAddrinfo->ai_canonname_len =
917
0
        CurAiCanonname.empty() ? 0 : CurAiCanonname.size() - 1;
918
0
    if (!CurAiCanonname.empty()) {
919
0
      std::memcpy(CurAiCanonname.data(), SysResItem->ai_canonname,
920
0
                  CurAiCanonname.size());
921
0
    }
922
923
    // process socket address
924
0
    auto &CurSockaddr = WasiSockaddrArray[Idx];
925
0
    CurSockaddr->sa_family = fromAddressFamily(SysResItem->ai_addr->sa_family);
926
0
    const auto &CurAiAddrSaData = AiAddrSaDataArray[Idx];
927
0
    std::memcpy(CurAiAddrSaData.data(), SysResItem->ai_addr->sa_data,
928
0
                CurAiAddrSaData.size());
929
0
    CurSockaddr->sa_data_len = __wasi_size_t(CurAiAddrSaData.size());
930
0
  }
931
0
  ResLength = SelectedLength;
932
933
0
  return {};
934
0
}
935
936
WasiExpect<INode> INode::sockOpen(__wasi_address_family_t AddressFamily,
937
0
                                  __wasi_sock_type_t SockType) noexcept {
938
0
  int SysProtocol = IPPROTO_IP;
939
0
  int SysDomain = 0;
940
0
  int SysType = 0;
941
942
0
  switch (AddressFamily) {
943
0
  case __WASI_ADDRESS_FAMILY_INET4:
944
0
    SysDomain = AF_INET;
945
0
    break;
946
0
  case __WASI_ADDRESS_FAMILY_INET6:
947
0
    SysDomain = AF_INET6;
948
0
    break;
949
0
  case __WASI_ADDRESS_FAMILY_AF_UNIX:
950
0
    SysDomain = AF_UNIX;
951
0
    break;
952
0
  default:
953
0
    return WasiUnexpect(__WASI_ERRNO_INVAL);
954
0
  }
955
956
0
  switch (SockType) {
957
0
  case __WASI_SOCK_TYPE_SOCK_DGRAM:
958
0
    SysType = SOCK_DGRAM;
959
0
    break;
960
0
  case __WASI_SOCK_TYPE_SOCK_STREAM:
961
0
    SysType = SOCK_STREAM;
962
0
    break;
963
0
  default:
964
0
    return WasiUnexpect(__WASI_ERRNO_INVAL);
965
0
  }
966
967
0
  if (auto NewFd = ::socket(SysDomain, SysType, SysProtocol);
968
0
      unlikely(NewFd < 0)) {
969
0
    return WasiUnexpect(fromErrNo(errno));
970
0
  } else {
971
0
    INode New(NewFd);
972
0
    return New;
973
0
  }
974
0
}
975
976
struct SockEmptyAddr {};
977
using VarAddrT = std::variant<SockEmptyAddr, sockaddr_storage, sockaddr,
978
                              sockaddr_in, sockaddr_in6, sockaddr_un>;
979
980
struct VarAddrBuf {
981
0
  template <typename T> sockaddr *operator()(T &V) {
982
0
    return reinterpret_cast<struct sockaddr *>(&V);
983
0
  }
Unexecuted instantiation: sockaddr* WasmEdge::Host::WASI::VarAddrBuf::operator()<sockaddr_storage>(sockaddr_storage&)
Unexecuted instantiation: sockaddr* WasmEdge::Host::WASI::VarAddrBuf::operator()<sockaddr>(sockaddr&)
Unexecuted instantiation: sockaddr* WasmEdge::Host::WASI::VarAddrBuf::operator()<sockaddr_in>(sockaddr_in&)
Unexecuted instantiation: sockaddr* WasmEdge::Host::WASI::VarAddrBuf::operator()<sockaddr_in6>(sockaddr_in6&)
Unexecuted instantiation: sockaddr* WasmEdge::Host::WASI::VarAddrBuf::operator()<sockaddr_un>(sockaddr_un&)
984
0
  sockaddr *operator()(SockEmptyAddr &) { return nullptr; }
985
};
986
987
struct VarAddrSize {
988
0
  template <typename T> int operator()(const T &) { return sizeof(T); }
Unexecuted instantiation: int WasmEdge::Host::WASI::VarAddrSize::operator()<sockaddr_storage>(sockaddr_storage const&)
Unexecuted instantiation: int WasmEdge::Host::WASI::VarAddrSize::operator()<sockaddr>(sockaddr const&)
Unexecuted instantiation: int WasmEdge::Host::WASI::VarAddrSize::operator()<sockaddr_in>(sockaddr_in const&)
Unexecuted instantiation: int WasmEdge::Host::WASI::VarAddrSize::operator()<sockaddr_in6>(sockaddr_in6 const&)
989
0
  int operator()(const SockEmptyAddr &) { return 0; }
990
0
  int operator()(const sockaddr_un &U) {
991
0
    const auto Len = strnlen(U.sun_path, sizeof(U.sun_path));
992
0
    if (Len == 0 || Len == sizeof(U.sun_path)) {
993
0
      return sizeof(sockaddr_un);
994
0
    }
995
0
    return static_cast<int>(offsetof(sockaddr_un, sun_path) + Len + 1);
996
0
  }
997
};
998
999
static VarAddrT sockAddressAssignHelper(__wasi_address_family_t AddrFamily,
1000
                                        const Span<const uint8_t> &Address,
1001
0
                                        uint16_t Port) {
1002
0
  VarAddrT Addr;
1003
0
  if (Address.size() == 0) {
1004
0
    Addr.emplace<SockEmptyAddr>();
1005
0
  } else if (AddrFamily == __WASI_ADDRESS_FAMILY_INET4) {
1006
0
    auto &ServerAddr4 = Addr.emplace<sockaddr_in>();
1007
1008
0
    ServerAddr4.sin_family = AF_INET;
1009
0
    ServerAddr4.sin_port = htons(Port);
1010
0
    assuming(Address.size() >= sizeof(in_addr));
1011
0
    std::memcpy(&ServerAddr4.sin_addr, Address.data(), sizeof(in_addr));
1012
0
  } else if (AddrFamily == __WASI_ADDRESS_FAMILY_INET6) {
1013
0
    auto &ServerAddr6 = Addr.emplace<sockaddr_in6>();
1014
1015
0
    ServerAddr6.sin6_family = AF_INET6;
1016
0
    ServerAddr6.sin6_port = htons(Port);
1017
0
    ServerAddr6.sin6_flowinfo = 0;
1018
0
    assuming(Address.size() >= sizeof(in6_addr));
1019
0
    std::memcpy(&ServerAddr6.sin6_addr, Address.data(), sizeof(in6_addr));
1020
0
  } else if (AddrFamily == __WASI_ADDRESS_FAMILY_AF_UNIX) {
1021
0
    auto &ServerAddrUN = Addr.emplace<sockaddr_un>();
1022
1023
0
    ServerAddrUN.sun_family = AF_UNIX;
1024
    // The length of sockaddr_un::sun_path depends on the current system.
1025
    // We should always check its size.
1026
0
    assuming(Address.size() >= sizeof(sockaddr_un::sun_path));
1027
0
    std::memcpy(&ServerAddrUN.sun_path, Address.data(),
1028
0
                sizeof(sockaddr_un::sun_path));
1029
0
  } else {
1030
0
    assumingUnreachable();
1031
0
  }
1032
1033
0
  return Addr;
1034
0
}
1035
1036
WasiExpect<void> INode::sockBind(__wasi_address_family_t AddressFamily,
1037
                                 Span<const uint8_t> Address,
1038
0
                                 uint16_t Port) noexcept {
1039
0
  auto AddressBuffer = sockAddressAssignHelper(AddressFamily, Address, Port);
1040
1041
0
  auto ServerAddr = std::visit(VarAddrBuf(), AddressBuffer);
1042
0
  int Size = std::visit(VarAddrSize(), AddressBuffer);
1043
1044
0
  if (auto Res = ::bind(Fd, ServerAddr, Size); unlikely(Res < 0)) {
1045
0
    return WasiUnexpect(fromErrNo(errno));
1046
0
  }
1047
0
  return {};
1048
0
}
1049
1050
0
WasiExpect<void> INode::sockListen(int32_t Backlog) noexcept {
1051
0
  if (auto Res = ::listen(Fd, Backlog); unlikely(Res < 0)) {
1052
0
    return WasiUnexpect(fromErrNo(errno));
1053
0
  }
1054
0
  return {};
1055
0
}
1056
1057
0
WasiExpect<INode> INode::sockAccept(__wasi_fdflags_t FdFlags) noexcept {
1058
0
  int NewFd;
1059
0
  if (NewFd = ::accept(Fd, nullptr, nullptr); unlikely(NewFd < 0)) {
1060
0
    return WasiUnexpect(fromErrNo(errno));
1061
0
  }
1062
1063
0
  INode New(NewFd);
1064
1065
0
  if (FdFlags & __WASI_FDFLAGS_NONBLOCK) {
1066
0
    int SysFlag = fcntl(NewFd, F_GETFL, 0);
1067
0
    SysFlag |= O_NONBLOCK;
1068
0
    if (auto Res = ::fcntl(NewFd, F_SETFL, SysFlag); unlikely(Res != 0)) {
1069
0
      return WasiUnexpect(fromErrNo(errno));
1070
0
    }
1071
0
  }
1072
1073
0
  return New;
1074
0
}
1075
1076
WasiExpect<void> INode::sockConnect(__wasi_address_family_t AddressFamily,
1077
                                    Span<const uint8_t> Address,
1078
0
                                    uint16_t Port) noexcept {
1079
0
  auto AddressBuffer = sockAddressAssignHelper(AddressFamily, Address, Port);
1080
1081
0
  auto ClientAddr = std::visit(VarAddrBuf(), AddressBuffer);
1082
0
  int Size = std::visit(VarAddrSize(), AddressBuffer);
1083
1084
0
  if (auto Res = ::connect(Fd, ClientAddr, Size); unlikely(Res < 0)) {
1085
0
    return WasiUnexpect(fromErrNo(errno));
1086
0
  }
1087
1088
0
  return {};
1089
0
}
1090
1091
WasiExpect<void> INode::sockRecv(Span<Span<uint8_t>> RiData,
1092
                                 __wasi_riflags_t RiFlags, __wasi_size_t &NRead,
1093
0
                                 __wasi_roflags_t &RoFlags) const noexcept {
1094
0
  return sockRecvFrom(RiData, RiFlags, nullptr, {}, nullptr, NRead, RoFlags);
1095
0
}
1096
1097
WasiExpect<void> INode::sockRecvFrom(Span<Span<uint8_t>> RiData,
1098
                                     __wasi_riflags_t RiFlags,
1099
                                     __wasi_address_family_t *AddressFamilyPtr,
1100
                                     Span<uint8_t> Address, uint16_t *PortPtr,
1101
                                     __wasi_size_t &NRead,
1102
0
                                     __wasi_roflags_t &RoFlags) const noexcept {
1103
0
  int SysRiFlags = 0;
1104
0
  if (RiFlags & __WASI_RIFLAGS_RECV_PEEK) {
1105
0
    SysRiFlags |= MSG_PEEK;
1106
0
  }
1107
0
  if (RiFlags & __WASI_RIFLAGS_RECV_WAITALL) {
1108
0
    SysRiFlags |= MSG_WAITALL;
1109
0
  }
1110
1111
0
  iovec SysIOVs[kIOVMax];
1112
0
  size_t SysIOVsSize = 0;
1113
0
  for (auto &IOV : RiData) {
1114
0
    SysIOVs[SysIOVsSize].iov_base = IOV.data();
1115
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
1116
0
    ++SysIOVsSize;
1117
0
  }
1118
1119
0
  const bool NeedAddress =
1120
0
      AddressFamilyPtr != nullptr || !Address.empty() || PortPtr != nullptr;
1121
0
  sockaddr_storage SockAddr = {};
1122
0
  msghdr SysMsgHdr;
1123
0
  if (NeedAddress) {
1124
0
    SysMsgHdr.msg_name = &SockAddr;
1125
0
    SysMsgHdr.msg_namelen = sizeof(SockAddr);
1126
0
  } else {
1127
0
    SysMsgHdr.msg_name = nullptr;
1128
0
    SysMsgHdr.msg_namelen = 0;
1129
0
  }
1130
0
  SysMsgHdr.msg_iov = SysIOVs;
1131
0
  SysMsgHdr.msg_iovlen = SysIOVsSize;
1132
0
  SysMsgHdr.msg_control = nullptr;
1133
0
  SysMsgHdr.msg_controllen = 0;
1134
0
  SysMsgHdr.msg_flags = 0;
1135
1136
  // Store recv bytes length and flags.
1137
0
  if (auto Res = ::recvmsg(Fd, &SysMsgHdr, SysRiFlags); unlikely(Res < 0)) {
1138
0
    return WasiUnexpect(fromErrNo(errno));
1139
0
  } else {
1140
0
    NRead = EndianValue(static_cast<__wasi_size_t>(Res)).le();
1141
0
  }
1142
1143
0
  if (NeedAddress) {
1144
0
    switch (SockAddr.ss_family) {
1145
0
    case AF_UNSPEC: {
1146
0
      spdlog::warn("remote address unavailable"sv);
1147
      // If ss_family is AF_UNSPEC, accessing the other members is
1148
      // undefined.
1149
0
      break;
1150
0
    }
1151
0
    case AF_INET: {
1152
0
      const auto &SockAddr4 = reinterpret_cast<sockaddr_in &>(SockAddr);
1153
0
      if (AddressFamilyPtr) {
1154
0
        *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET4;
1155
0
      }
1156
0
      if (Address.size() >= sizeof(in_addr)) {
1157
0
        std::memcpy(Address.data(), &SockAddr4.sin_addr, sizeof(in_addr));
1158
0
      }
1159
0
      if (PortPtr != nullptr) {
1160
0
        *PortPtr = SockAddr4.sin_port;
1161
0
      }
1162
0
      break;
1163
0
    }
1164
0
    case AF_INET6: {
1165
0
      const auto &SockAddr6 = reinterpret_cast<sockaddr_in6 &>(SockAddr);
1166
0
      if (AddressFamilyPtr) {
1167
0
        *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET6;
1168
0
      }
1169
0
      if (Address.size() >= sizeof(in6_addr)) {
1170
0
        std::memcpy(Address.data(), &SockAddr6.sin6_addr, sizeof(in6_addr));
1171
0
      }
1172
0
      if (PortPtr != nullptr) {
1173
0
        *PortPtr = SockAddr6.sin6_port;
1174
0
      }
1175
0
      break;
1176
0
    }
1177
0
    case AF_UNIX: {
1178
0
      const auto &SockAddrUN = reinterpret_cast<sockaddr_un &>(SockAddr);
1179
0
      if (AddressFamilyPtr) {
1180
0
        *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_AF_UNIX;
1181
0
      }
1182
0
      if (Address.size() >= sizeof(sockaddr_un::sun_path)) {
1183
0
        std::memcpy(Address.data(), &SockAddrUN.sun_path,
1184
0
                    sizeof(sockaddr_un::sun_path));
1185
0
      } else {
1186
0
        return WasiUnexpect(__WASI_ERRNO_INVAL);
1187
0
      }
1188
0
      break;
1189
0
    }
1190
0
    default:
1191
0
      return WasiUnexpect(__WASI_ERRNO_NOSYS);
1192
0
    }
1193
0
  }
1194
1195
0
  RoFlags = static_cast<__wasi_roflags_t>(0);
1196
0
  if (SysMsgHdr.msg_flags & MSG_TRUNC) {
1197
0
    RoFlags |= __WASI_ROFLAGS_RECV_DATA_TRUNCATED;
1198
0
  }
1199
0
  RoFlags = EndianValue(RoFlags).le();
1200
1201
0
  return {};
1202
0
}
1203
1204
WasiExpect<void> INode::sockSend(Span<Span<const uint8_t>> SiData,
1205
                                 __wasi_siflags_t SiFlags,
1206
0
                                 __wasi_size_t &NWritten) const noexcept {
1207
0
  return sockSendTo(SiData, SiFlags, __WASI_ADDRESS_FAMILY_UNSPEC, {}, 0,
1208
0
                    NWritten);
1209
0
}
1210
1211
WasiExpect<void> INode::sockSendTo(Span<Span<const uint8_t>> SiData,
1212
                                   __wasi_siflags_t,
1213
                                   __wasi_address_family_t AddressFamily,
1214
                                   Span<const uint8_t> Address, uint16_t Port,
1215
0
                                   __wasi_size_t &NWritten) const noexcept {
1216
0
  int SysSiFlags = MSG_NOSIGNAL;
1217
0
  sockaddr *ClientAddr = nullptr;
1218
0
  socklen_t MsgNameLen = 0;
1219
0
  VarAddrT AddressBuffer;
1220
1221
0
  if (Address.size()) {
1222
0
    AddressBuffer = sockAddressAssignHelper(AddressFamily, Address, Port);
1223
0
    ClientAddr = std::visit(VarAddrBuf(), AddressBuffer);
1224
0
    MsgNameLen = std::visit(VarAddrSize(), AddressBuffer);
1225
0
  }
1226
1227
0
  iovec SysIOVs[kIOVMax];
1228
0
  size_t SysIOVsSize = 0;
1229
0
  for (auto &IOV : SiData) {
1230
0
    SysIOVs[SysIOVsSize].iov_base = const_cast<uint8_t *>(IOV.data());
1231
0
    SysIOVs[SysIOVsSize].iov_len = IOV.size();
1232
0
    ++SysIOVsSize;
1233
0
  }
1234
1235
0
  msghdr SysMsgHdr;
1236
0
  SysMsgHdr.msg_name = MsgNameLen == 0 ? nullptr : ClientAddr;
1237
0
  SysMsgHdr.msg_namelen = MsgNameLen;
1238
0
  SysMsgHdr.msg_iov = SysIOVs;
1239
0
  SysMsgHdr.msg_iovlen = SysIOVsSize;
1240
0
  SysMsgHdr.msg_control = nullptr;
1241
0
  SysMsgHdr.msg_controllen = 0;
1242
1243
  // Store recv bytes length and flags.
1244
0
  if (auto Res = ::sendmsg(Fd, &SysMsgHdr, SysSiFlags); unlikely(Res < 0)) {
1245
0
    return WasiUnexpect(fromErrNo(errno));
1246
0
  } else {
1247
0
    NWritten = EndianValue(static_cast<__wasi_size_t>(Res)).le();
1248
0
  }
1249
1250
0
  return {};
1251
0
}
1252
1253
0
WasiExpect<void> INode::sockShutdown(__wasi_sdflags_t SdFlags) const noexcept {
1254
0
  int SysFlags = 0;
1255
0
  if (SdFlags == __WASI_SDFLAGS_RD) {
1256
0
    SysFlags = SHUT_RD;
1257
0
  } else if (SdFlags == __WASI_SDFLAGS_WR) {
1258
0
    SysFlags = SHUT_WR;
1259
0
  } else if (SdFlags == (__WASI_SDFLAGS_RD | __WASI_SDFLAGS_WR)) {
1260
0
    SysFlags = SHUT_RDWR;
1261
0
  }
1262
1263
0
  if (auto Res = ::shutdown(Fd, SysFlags); unlikely(Res < 0)) {
1264
0
    return WasiUnexpect(fromErrNo(errno));
1265
0
  }
1266
1267
0
  return {};
1268
0
}
1269
1270
WasiExpect<void> INode::sockGetOpt(__wasi_sock_opt_level_t SockOptLevel,
1271
                                   __wasi_sock_opt_so_t SockOptName,
1272
0
                                   Span<uint8_t> &Flag) const noexcept {
1273
0
  auto SysSockOptLevel = toSockOptLevel(SockOptLevel);
1274
0
  auto SysSockOptName = toSockOptSoName(SockOptName);
1275
0
  socklen_t Size = static_cast<socklen_t>(Flag.size());
1276
0
  if (auto Res =
1277
0
          ::getsockopt(Fd, SysSockOptLevel, SysSockOptName, Flag.data(), &Size);
1278
0
      unlikely(Res < 0)) {
1279
0
    return WasiUnexpect(fromErrNo(errno));
1280
0
  }
1281
1282
0
  switch (SockOptName) {
1283
0
  case __WASI_SOCK_OPT_SO_ERROR: {
1284
0
    assuming(Size == sizeof(int32_t));
1285
0
    Flag = Flag.first(static_cast<size_t>(Size));
1286
0
    auto *Error = reinterpret_cast<int32_t *>(Flag.data());
1287
0
    *Error = static_cast<int32_t>(fromErrNo(*Error));
1288
0
    break;
1289
0
  }
1290
0
  case __WASI_SOCK_OPT_SO_TYPE: {
1291
0
    assuming(Size == sizeof(int32_t));
1292
0
    Flag = Flag.first(static_cast<size_t>(Size));
1293
0
    assuming(Flag.size() == sizeof(int32_t));
1294
0
    auto &SockType = *reinterpret_cast<int32_t *>(Flag.data());
1295
0
    SockType = static_cast<int32_t>(fromSockType(SockType));
1296
0
    break;
1297
0
  }
1298
0
  default:
1299
0
    Flag = Flag.first(static_cast<size_t>(Size));
1300
0
  }
1301
1302
0
  return {};
1303
0
}
1304
1305
WasiExpect<void> INode::sockSetOpt(__wasi_sock_opt_level_t SockOptLevel,
1306
                                   __wasi_sock_opt_so_t SockOptName,
1307
0
                                   Span<const uint8_t> Flag) const noexcept {
1308
0
  auto SysSockOptLevel = toSockOptLevel(SockOptLevel);
1309
0
  auto SysSockOptName = toSockOptSoName(SockOptName);
1310
1311
0
  if (auto Res = ::setsockopt(Fd, SysSockOptLevel, SysSockOptName, Flag.data(),
1312
0
                              Flag.size());
1313
0
      unlikely(Res < 0)) {
1314
0
    return WasiUnexpect(fromErrNo(errno));
1315
0
  }
1316
1317
0
  return {};
1318
0
}
1319
1320
WasiExpect<void>
1321
INode::sockGetLocalAddr(__wasi_address_family_t *AddressFamilyPtr,
1322
                        Span<uint8_t> Address,
1323
0
                        uint16_t *PortPtr) const noexcept {
1324
0
  sockaddr_storage SocketAddr = {};
1325
0
  socklen_t Slen = sizeof(SocketAddr);
1326
1327
0
  if (auto Res =
1328
0
          ::getsockname(Fd, reinterpret_cast<sockaddr *>(&SocketAddr), &Slen);
1329
0
      unlikely(Res < 0)) {
1330
0
    return WasiUnexpect(fromErrNo(errno));
1331
0
  }
1332
1333
0
  switch (SocketAddr.ss_family) {
1334
0
  case AF_INET: {
1335
0
    if (Address.size() < sizeof(in_addr)) {
1336
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1337
0
    }
1338
0
    const auto &SocketAddr4 = reinterpret_cast<sockaddr_in &>(SocketAddr);
1339
0
    if (AddressFamilyPtr) {
1340
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET4;
1341
0
    }
1342
0
    if (PortPtr) {
1343
0
      *PortPtr = ntohs(SocketAddr4.sin_port);
1344
0
    }
1345
0
    std::memcpy(Address.data(), &SocketAddr4.sin_addr, sizeof(in_addr));
1346
0
    return {};
1347
0
  }
1348
0
  case AF_INET6: {
1349
0
    if (Address.size() < sizeof(in6_addr)) {
1350
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1351
0
    }
1352
0
    const auto &SocketAddr6 = reinterpret_cast<sockaddr_in6 &>(SocketAddr);
1353
0
    if (AddressFamilyPtr) {
1354
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET6;
1355
0
    }
1356
0
    if (PortPtr) {
1357
0
      *PortPtr = ntohs(SocketAddr6.sin6_port);
1358
0
    }
1359
0
    std::memcpy(Address.data(), &SocketAddr6.sin6_addr, sizeof(in6_addr));
1360
0
    return {};
1361
0
  }
1362
0
  case AF_UNIX: {
1363
0
    if (Address.size() < sizeof(sockaddr_un::sun_path)) {
1364
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1365
0
    }
1366
0
    const auto &SocketAddrUN = reinterpret_cast<sockaddr_un &>(SocketAddr);
1367
0
    if (AddressFamilyPtr) {
1368
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_AF_UNIX;
1369
0
    }
1370
1371
0
    std::memcpy(Address.data(), &SocketAddrUN.sun_path,
1372
0
                sizeof(sockaddr_un::sun_path));
1373
0
    return {};
1374
0
  }
1375
0
  default:
1376
0
    return WasiUnexpect(__WASI_ERRNO_NOSYS);
1377
0
  }
1378
0
}
1379
1380
WasiExpect<void>
1381
INode::sockGetPeerAddr(__wasi_address_family_t *AddressFamilyPtr,
1382
                       Span<uint8_t> Address,
1383
0
                       uint16_t *PortPtr) const noexcept {
1384
0
  sockaddr_storage SocketAddr = {};
1385
0
  socklen_t Slen = sizeof(SocketAddr);
1386
1387
0
  if (auto Res =
1388
0
          ::getpeername(Fd, reinterpret_cast<sockaddr *>(&SocketAddr), &Slen);
1389
0
      unlikely(Res < 0)) {
1390
0
    return WasiUnexpect(fromErrNo(errno));
1391
0
  }
1392
1393
0
  switch (SocketAddr.ss_family) {
1394
0
  case AF_INET: {
1395
0
    if (Address.size() < sizeof(in_addr)) {
1396
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1397
0
    }
1398
0
    const auto &SocketAddr4 = reinterpret_cast<sockaddr_in &>(SocketAddr);
1399
0
    if (AddressFamilyPtr) {
1400
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET4;
1401
0
    }
1402
0
    if (PortPtr) {
1403
0
      *PortPtr = ntohs(SocketAddr4.sin_port);
1404
0
    }
1405
0
    std::memcpy(Address.data(), &SocketAddr4.sin_addr, sizeof(in_addr));
1406
0
    return {};
1407
0
  }
1408
0
  case AF_INET6: {
1409
0
    if (Address.size() < sizeof(in6_addr)) {
1410
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1411
0
    }
1412
0
    const auto &SocketAddr6 = reinterpret_cast<sockaddr_in6 &>(SocketAddr);
1413
0
    if (AddressFamilyPtr) {
1414
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_INET6;
1415
0
    }
1416
0
    if (PortPtr) {
1417
0
      *PortPtr = ntohs(SocketAddr6.sin6_port);
1418
0
    }
1419
0
    std::memcpy(Address.data(), &SocketAddr6.sin6_addr, sizeof(in6_addr));
1420
0
    return {};
1421
0
  }
1422
0
  case AF_UNIX: {
1423
0
    if (Address.size() < sizeof(sockaddr_un::sun_path)) {
1424
0
      return WasiUnexpect(__WASI_ERRNO_NOMEM);
1425
0
    }
1426
0
    const auto &SocketAddrUN = reinterpret_cast<sockaddr_un &>(SocketAddr);
1427
0
    if (AddressFamilyPtr) {
1428
0
      *AddressFamilyPtr = __WASI_ADDRESS_FAMILY_AF_UNIX;
1429
0
    }
1430
1431
0
    std::memcpy(Address.data(), &SocketAddrUN.sun_path,
1432
0
                sizeof(sockaddr_un::sun_path));
1433
0
    return {};
1434
0
  }
1435
0
  default:
1436
0
    return WasiUnexpect(__WASI_ERRNO_NOSYS);
1437
0
  }
1438
0
}
1439
1440
0
__wasi_filetype_t INode::unsafeFiletype() const noexcept {
1441
0
  return fromFileType(static_cast<mode_t>(Stat->st_mode));
1442
0
}
1443
1444
0
WasiExpect<__wasi_filetype_t> INode::filetype() const noexcept {
1445
0
  if (!Stat) {
1446
0
    EXPECTED_TRY(updateStat());
1447
0
  }
1448
0
  return unsafeFiletype();
1449
0
}
1450
1451
0
bool INode::isDirectory() const noexcept {
1452
0
  if (!Stat) {
1453
0
    if (!updateStat()) {
1454
0
      return false;
1455
0
    }
1456
0
  }
1457
0
  return (Stat->st_mode & S_IFMT) == S_IFDIR;
1458
0
}
1459
1460
0
bool INode::isSymlink() const noexcept {
1461
0
  if (!Stat) {
1462
0
    if (!updateStat()) {
1463
0
      return false;
1464
0
    }
1465
0
  }
1466
0
  return (Stat->st_mode & S_IFMT) == S_IFLNK;
1467
0
}
1468
1469
0
WasiExpect<__wasi_filesize_t> INode::filesize() const noexcept {
1470
0
  if (!Stat) {
1471
0
    EXPECTED_TRY(updateStat());
1472
0
  }
1473
0
  return Stat->st_size;
1474
0
}
1475
1476
0
bool INode::canBrowse() const noexcept {
1477
0
  return ::faccessat(Fd, ".", X_OK, 0) == 0;
1478
0
}
1479
1480
0
WasiExpect<void> INode::updateStat() const noexcept {
1481
0
  Stat.emplace();
1482
0
  if (unlikely(::fstat(Fd, &*Stat) != 0)) {
1483
0
    return WasiUnexpect(fromErrNo(errno));
1484
0
  }
1485
0
  return {};
1486
0
}
1487
1488
WasiExpect<Poller::Timer>
1489
0
PollerContext::acquireTimer(__wasi_clockid_t Clock) noexcept {
1490
0
  std::unique_lock Lock(TimerMutex);
1491
0
  if (auto &Timers = TimerPool.try_emplace(Clock).first->second;
1492
0
      Timers.empty()) {
1493
0
    Poller::Timer Result(Clock);
1494
0
    if (auto Res = Result.create(); unlikely(!Res)) {
1495
0
      return WasiUnexpect(fromErrNo(errno));
1496
0
    }
1497
0
    return Result;
1498
0
  } else {
1499
0
    Poller::Timer Result(std::move(Timers.back()));
1500
0
    Timers.pop_back();
1501
0
    return Result;
1502
0
  }
1503
0
}
1504
1505
0
void PollerContext::releaseTimer(Poller::Timer &&Timer) noexcept {
1506
0
  std::unique_lock Lock(TimerMutex);
1507
0
  const auto Clock = Timer.Clock;
1508
0
  try {
1509
0
    TimerPool.try_emplace(Clock).first->second.push_back(std::move(Timer));
1510
0
  } catch (std::bad_alloc &) {
1511
    // giving up caching timer
1512
0
  }
1513
0
}
1514
1515
#if __GLIBC_PREREQ(2, 8)
1516
0
WasiExpect<void> Poller::Timer::create() noexcept {
1517
0
  if (const auto NewFd =
1518
0
          ::timerfd_create(toClockId(Clock), TFD_NONBLOCK | TFD_CLOEXEC);
1519
0
      unlikely(NewFd < 0)) {
1520
0
    return WasiUnexpect(fromErrNo(errno));
1521
0
  } else {
1522
0
    FdHolder::emplace(NewFd);
1523
0
  }
1524
0
  return {};
1525
0
}
1526
1527
WasiExpect<void> Poller::Timer::setTime(__wasi_timestamp_t Timeout,
1528
                                        __wasi_timestamp_t,
1529
0
                                        __wasi_subclockflags_t Flags) noexcept {
1530
  // disarm timer
1531
0
  {
1532
0
    itimerspec Spec{toTimespec(0), toTimespec(0)};
1533
0
    if (auto Res = ::timerfd_settime(Fd, 0, &Spec, nullptr);
1534
0
        unlikely(Res < 0)) {
1535
0
      errno = 0;
1536
0
    }
1537
0
  }
1538
1539
0
  int SysFlags = 0;
1540
0
  if (Flags & __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) {
1541
0
    SysFlags |= TFD_TIMER_ABSTIME;
1542
0
  }
1543
  // Zero timeout has a special meaning. When itimerspec is set to 0, it will
1544
  // disarm the timer.
1545
0
  Timeout = std::max<__wasi_timestamp_t>(Timeout, 1U);
1546
0
  itimerspec Spec{toTimespec(0), toTimespec(Timeout)};
1547
0
  if (auto Res = ::timerfd_settime(Fd, SysFlags, &Spec, nullptr);
1548
0
      unlikely(Res < 0)) {
1549
0
    return WasiUnexpect(fromErrNo(errno));
1550
0
  }
1551
1552
0
  return {};
1553
0
}
1554
#else
1555
namespace {
1556
static void sigevCallback(union sigval Value) noexcept {
1557
  const uint64_t One = 1;
1558
  ::write(Value.sival_int, &One, sizeof(One));
1559
}
1560
1561
WasiExpect<void> setTimerPipeFlags(int Fd) noexcept {
1562
  const int StatusFlags = ::fcntl(Fd, F_GETFL);
1563
  if (unlikely(StatusFlags < 0)) {
1564
    return WasiUnexpect(fromErrNo(errno));
1565
  }
1566
1567
  if (unlikely(::fcntl(Fd, F_SETFD, FD_CLOEXEC) != 0 ||
1568
               ::fcntl(Fd, F_SETFL, StatusFlags | O_NONBLOCK) != 0)) {
1569
    return WasiUnexpect(fromErrNo(errno));
1570
  }
1571
1572
  return {};
1573
}
1574
} // namespace
1575
1576
WasiExpect<void> Poller::Timer::create() noexcept {
1577
  {
1578
    int PipeFd[2] = {-1, -1};
1579
1580
    if (auto Res = ::pipe(PipeFd); unlikely(Res != 0)) {
1581
      return WasiUnexpect(fromErrNo(errno));
1582
    }
1583
    FdHolder::emplace(PipeFd[0]);
1584
    Notify.emplace(PipeFd[1]);
1585
  }
1586
1587
  timer_t TId;
1588
  {
1589
    sigevent Event;
1590
    Event.sigev_notify = SIGEV_THREAD;
1591
    Event.sigev_notify_function = &sigevCallback;
1592
    Event.sigev_value.sival_int = Notify.Fd;
1593
    Event.sigev_notify_attributes = nullptr;
1594
1595
    EXPECTED_TRY(setTimerPipeFlags(Fd));
1596
    EXPECTED_TRY(setTimerPipeFlags(Notify.Fd));
1597
1598
    if (unlikely(::timer_create(toClockId(Clock), &Event, &TId) < 0)) {
1599
      return WasiUnexpect(fromErrNo(errno));
1600
    }
1601
  }
1602
  TimerId.emplace(TId);
1603
  return {};
1604
}
1605
1606
WasiExpect<void> Poller::Timer::setTime(__wasi_timestamp_t Timeout,
1607
                                        __wasi_timestamp_t,
1608
                                        __wasi_subclockflags_t Flags) noexcept {
1609
  if (unlikely(!TimerId.Id)) {
1610
    return WasiUnexpect(__WASI_ERRNO_INVAL);
1611
  }
1612
1613
  // disarm timer
1614
  {
1615
    itimerspec Spec{toTimespec(0), toTimespec(0)};
1616
    if (auto Res = ::timer_settime(*TimerId.Id, 0, &Spec, nullptr);
1617
        unlikely(Res < 0)) {
1618
      errno = 0;
1619
    }
1620
  }
1621
  // reset pipe
1622
  {
1623
    uint64_t Buffer[16];
1624
    while (true) {
1625
      if (auto Res = ::read(Fd, &Buffer, sizeof(Buffer)); Res <= 0) {
1626
        break;
1627
      }
1628
    }
1629
  }
1630
1631
  int SysFlags = 0;
1632
  if (Flags & __WASI_SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME) {
1633
    SysFlags |= TIMER_ABSTIME;
1634
  }
1635
  // Zero timeout has a special meaning. When itimerspec is set to 0, it will
1636
  // disarm the timer.
1637
  Timeout = std::max<__wasi_timestamp_t>(Timeout, 1U);
1638
  itimerspec Spec{toTimespec(0), toTimespec(Timeout)};
1639
  if (auto Res = ::timer_settime(*TimerId.Id, SysFlags, &Spec, nullptr);
1640
      unlikely(Res < 0)) {
1641
    return WasiUnexpect(fromErrNo(errno));
1642
  }
1643
  return {};
1644
}
1645
#endif
1646
1647
Poller::Poller(PollerContext &C) noexcept
1648
0
    : FdHolder(
1649
0
#if __GLIBC_PREREQ(2, 9)
1650
0
          ::epoll_create1(EPOLL_CLOEXEC)
1651
#else
1652
          // Guessing a number that might be sufficient for linux before 2.6.8
1653
          ::epoll_create(32)
1654
#endif
1655
0
              ),
1656
0
      Ctx(&C) {
1657
#if !__GLIBC_PREREQ(2, 9)
1658
  if (auto Res = ::fcntl(Fd, F_SETFD, FD_CLOEXEC); unlikely(Res != 0)) {
1659
    FdHolder::reset();
1660
    return;
1661
  }
1662
#endif
1663
0
}
1664
1665
0
WasiExpect<void> Poller::prepare(Span<__wasi_event_t> E) noexcept {
1666
0
  WasiEvents = E;
1667
0
  try {
1668
0
    Events.reserve(E.size());
1669
0
    Timers.reserve(E.size());
1670
0
    EPollEvents.reserve(E.size());
1671
0
  } catch (std::bad_alloc &) {
1672
0
    return WasiUnexpect(__WASI_ERRNO_NOMEM);
1673
0
  }
1674
1675
0
  return {};
1676
0
}
1677
1678
void Poller::clock(__wasi_clockid_t Clock, __wasi_timestamp_t Timeout,
1679
                   __wasi_timestamp_t Precision, __wasi_subclockflags_t Flags,
1680
0
                   __wasi_userdata_t UserData) noexcept {
1681
0
  assuming(Events.size() < WasiEvents.size());
1682
0
  auto &Event = Events.emplace_back();
1683
0
  Event.Valid = false;
1684
0
  Event.userdata = UserData;
1685
0
  Event.type = __WASI_EVENTTYPE_CLOCK;
1686
1687
0
  if (auto Res = Ctx->acquireTimer(Clock); unlikely(!Res)) {
1688
0
    Event.Valid = true;
1689
0
    Event.error = Res.error();
1690
0
    return;
1691
0
  } else {
1692
0
    Timers.emplace_back(std::move(*Res));
1693
0
  }
1694
1695
0
  auto &Timer = Timers.back();
1696
0
  if (auto Res = Timer.setTime(Timeout, Precision, Flags); unlikely(!Res)) {
1697
0
    Ctx->releaseTimer(std::move(Timer));
1698
0
    Timers.pop_back();
1699
0
    Event.Valid = true;
1700
0
    Event.error = Res.error();
1701
0
    return;
1702
0
  }
1703
1704
0
  assuming(Timer.Fd != Fd);
1705
0
  try {
1706
0
    auto [Iter, Added] = FdDatas.try_emplace(Timer.Fd);
1707
1708
0
    Iter->second.ReadEvent = &Event;
1709
0
    assuming(Added);
1710
1711
0
    epoll_event EPollEvent;
1712
0
    EPollEvent.events = EPOLLIN;
1713
0
#if defined(EPOLLRDHUP)
1714
0
    EPollEvent.events |= EPOLLRDHUP;
1715
0
#endif
1716
0
    EPollEvent.data.fd = Timer.Fd;
1717
1718
0
    if (auto Res = ::epoll_ctl(Fd, EPOLL_CTL_ADD, Timer.Fd, &EPollEvent);
1719
0
        unlikely(Res < 0)) {
1720
0
      FdDatas.erase(Iter);
1721
0
      Ctx->releaseTimer(std::move(Timer));
1722
0
      Timers.pop_back();
1723
0
      Event.Valid = true;
1724
0
      Event.error = fromErrNo(errno);
1725
0
      return;
1726
0
    }
1727
1728
0
    return;
1729
0
  } catch (std::bad_alloc &) {
1730
0
    Ctx->releaseTimer(std::move(Timer));
1731
0
    Timers.pop_back();
1732
0
    Event.Valid = true;
1733
0
    Event.error = __WASI_ERRNO_NOMEM;
1734
0
    return;
1735
0
  }
1736
0
}
1737
1738
0
void Poller::close(const INode &Node) noexcept {
1739
0
  FdDatas.erase(Node.Fd);
1740
0
  OldFdDatas.erase(Node.Fd);
1741
0
}
1742
1743
void Poller::read(const INode &Node, TriggerType Trigger,
1744
0
                  __wasi_userdata_t UserData) noexcept {
1745
0
  assuming(Events.size() < WasiEvents.size());
1746
0
  auto &Event = Events.emplace_back();
1747
0
  Event.Valid = false;
1748
0
  Event.userdata = UserData;
1749
0
  Event.type = __WASI_EVENTTYPE_FD_READ;
1750
1751
0
  assuming(Node.Fd != Fd);
1752
0
  try {
1753
0
    auto [Iter, Added] = FdDatas.try_emplace(Node.Fd);
1754
0
    const bool New = OldFdDatas.find(Node.Fd) == OldFdDatas.end();
1755
1756
0
    if (unlikely(!Added && Iter->second.ReadEvent != nullptr)) {
1757
0
      Event.Valid = true;
1758
0
      Event.error = __WASI_ERRNO_EXIST;
1759
0
      return;
1760
0
    }
1761
0
    Iter->second.ReadEvent = &Event;
1762
1763
0
    epoll_event EPollEvent;
1764
0
    EPollEvent.events = EPOLLIN;
1765
0
    if (!Added) {
1766
0
      assuming(Iter->second.WriteEvent != nullptr);
1767
0
      EPollEvent.events |= EPOLLOUT;
1768
0
    }
1769
0
    if (Trigger == TriggerType::Edge) {
1770
0
      EPollEvent.events |= EPOLLET;
1771
0
    }
1772
0
#if defined(EPOLLRDHUP)
1773
0
    EPollEvent.events |= EPOLLRDHUP;
1774
0
#endif
1775
0
    EPollEvent.data.fd = Node.Fd;
1776
1777
0
    if (likely(Added) && New) {
1778
0
      if (auto Res = ::epoll_ctl(Fd, EPOLL_CTL_ADD, Node.Fd, &EPollEvent);
1779
0
          unlikely(Res < 0)) {
1780
0
        FdDatas.erase(Iter);
1781
0
        Event.Valid = true;
1782
0
        Event.error = fromErrNo(errno);
1783
0
        return;
1784
0
      }
1785
0
    } else {
1786
0
      if (auto Res = ::epoll_ctl(Fd, EPOLL_CTL_MOD, Node.Fd, &EPollEvent);
1787
0
          unlikely(Res < 0)) {
1788
0
        Event.Valid = true;
1789
0
        Event.error = fromErrNo(errno);
1790
0
        return;
1791
0
      }
1792
0
    }
1793
0
  } catch (std::bad_alloc &) {
1794
0
    Event.Valid = true;
1795
0
    Event.error = __WASI_ERRNO_NOMEM;
1796
0
    return;
1797
0
  }
1798
0
}
1799
1800
void Poller::write(const INode &Node, TriggerType Trigger,
1801
0
                   __wasi_userdata_t UserData) noexcept {
1802
0
  assuming(Events.size() < WasiEvents.size());
1803
0
  auto &Event = Events.emplace_back();
1804
0
  Event.Valid = false;
1805
0
  Event.userdata = UserData;
1806
0
  Event.type = __WASI_EVENTTYPE_FD_WRITE;
1807
1808
0
  assuming(Node.Fd != Fd);
1809
0
  try {
1810
0
    auto [Iter, Added] = FdDatas.try_emplace(Node.Fd);
1811
0
    const bool New = OldFdDatas.find(Node.Fd) == OldFdDatas.end();
1812
1813
0
    if (unlikely(!Added && Iter->second.WriteEvent != nullptr)) {
1814
0
      Event.Valid = true;
1815
0
      Event.error = __WASI_ERRNO_EXIST;
1816
0
      return;
1817
0
    }
1818
0
    Iter->second.WriteEvent = &Event;
1819
1820
0
    epoll_event EPollEvent;
1821
0
    EPollEvent.events = EPOLLOUT;
1822
0
    if (!Added) {
1823
0
      assuming(Iter->second.ReadEvent != nullptr);
1824
0
      EPollEvent.events |= EPOLLIN;
1825
0
    }
1826
0
    if (Trigger == TriggerType::Edge) {
1827
0
      EPollEvent.events |= EPOLLET;
1828
0
    }
1829
0
#if defined(EPOLLRDHUP)
1830
0
    EPollEvent.events |= EPOLLRDHUP;
1831
0
#endif
1832
0
    EPollEvent.data.fd = Node.Fd;
1833
1834
0
    if (likely(Added) && New) {
1835
0
      if (auto Res = ::epoll_ctl(Fd, EPOLL_CTL_ADD, Node.Fd, &EPollEvent);
1836
0
          unlikely(Res < 0)) {
1837
0
        FdDatas.erase(Iter);
1838
0
        Event.Valid = true;
1839
0
        Event.error = fromErrNo(errno);
1840
0
        return;
1841
0
      }
1842
0
    } else {
1843
0
      if (auto Res = ::epoll_ctl(Fd, EPOLL_CTL_MOD, Node.Fd, &EPollEvent);
1844
0
          unlikely(Res < 0)) {
1845
0
        Event.Valid = true;
1846
0
        Event.error = fromErrNo(errno);
1847
0
        return;
1848
0
      }
1849
0
    }
1850
0
  } catch (std::bad_alloc &) {
1851
0
    Event.Valid = true;
1852
0
    Event.error = __WASI_ERRNO_NOMEM;
1853
0
    return;
1854
0
  }
1855
0
}
1856
1857
0
void Poller::wait() noexcept {
1858
0
  for (const auto &[NodeFd, FdData] : OldFdDatas) {
1859
0
    if (auto Iter = FdDatas.find(NodeFd); Iter == FdDatas.end()) {
1860
      // Remove unused event, ignore failed.
1861
      // In kernel before 2.6.9, EPOLL_CTL_DEL required a non-null pointer. Use
1862
      // `this` as the dummy parameter.
1863
0
      ::epoll_ctl(Fd, EPOLL_CTL_DEL, NodeFd,
1864
0
                  reinterpret_cast<struct epoll_event *>(this));
1865
0
    }
1866
0
  }
1867
1868
  // Nothing is subscribed: epoll_wait rejects an empty event buffer.
1869
0
  if (Events.empty()) {
1870
0
    return;
1871
0
  }
1872
1873
0
  EPollEvents.resize(Events.size());
1874
0
  const int Count =
1875
0
      ::epoll_wait(Fd, EPollEvents.data(), EPollEvents.size(), -1);
1876
0
  if (unlikely(Count < 0)) {
1877
0
    const auto Error = fromErrNo(errno);
1878
0
    for (auto &Event : Events) {
1879
0
      Event.Valid = true;
1880
0
      Event.error = Error;
1881
0
    }
1882
0
    return;
1883
0
  }
1884
1885
0
  auto ProcessEvent = [](const struct epoll_event &EPollEvent,
1886
0
                         OptionalEvent &Event) noexcept {
1887
0
    Event.Valid = true;
1888
0
    Event.error = __WASI_ERRNO_SUCCESS;
1889
0
    switch (Event.type) {
1890
0
    case __WASI_EVENTTYPE_CLOCK:
1891
0
      break;
1892
0
    case __WASI_EVENTTYPE_FD_READ: {
1893
0
      Event.fd_readwrite.flags = static_cast<__wasi_eventrwflags_t>(0);
1894
0
      if (EPollEvent.events & EPOLLHUP) {
1895
0
        Event.fd_readwrite.flags |= __WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP;
1896
0
      }
1897
0
      bool UnknownNBytes = false;
1898
0
      int ReadBufUsed = 0;
1899
0
      if (auto Res = ::ioctl(EPollEvent.data.fd, FIONREAD, &ReadBufUsed);
1900
0
          unlikely(Res == 0)) {
1901
0
        UnknownNBytes = true;
1902
0
      }
1903
0
      if (UnknownNBytes) {
1904
0
        Event.fd_readwrite.nbytes = 1;
1905
0
      } else {
1906
0
        Event.fd_readwrite.nbytes = ReadBufUsed;
1907
0
      }
1908
0
      break;
1909
0
    }
1910
0
    case __WASI_EVENTTYPE_FD_WRITE: {
1911
0
      Event.fd_readwrite.flags = static_cast<__wasi_eventrwflags_t>(0);
1912
0
      if (EPollEvent.events & EPOLLHUP) {
1913
0
        Event.fd_readwrite.flags |= __WASI_EVENTRWFLAGS_FD_READWRITE_HANGUP;
1914
0
      }
1915
0
      bool UnknownNBytes = false;
1916
0
      int WriteBufSize = 0;
1917
0
      socklen_t IntSize = sizeof(WriteBufSize);
1918
0
      if (auto Res = ::getsockopt(EPollEvent.data.fd, SOL_SOCKET, SO_SNDBUF,
1919
0
                                  &WriteBufSize, &IntSize);
1920
0
          unlikely(Res != 0)) {
1921
0
        UnknownNBytes = true;
1922
0
      }
1923
0
      int WriteBufUsed = 0;
1924
0
      if (auto Res = ::ioctl(EPollEvent.data.fd, TIOCOUTQ, &WriteBufUsed);
1925
0
          unlikely(Res != 0)) {
1926
0
        UnknownNBytes = true;
1927
0
      }
1928
0
      if (UnknownNBytes) {
1929
0
        Event.fd_readwrite.nbytes = 1;
1930
0
      } else {
1931
0
        Event.fd_readwrite.nbytes = WriteBufSize - WriteBufUsed;
1932
0
      }
1933
0
      break;
1934
0
    }
1935
0
    }
1936
0
  };
1937
1938
0
  for (int I = 0; I < Count; ++I) {
1939
0
    const auto &EPollEvent = EPollEvents[I];
1940
0
    const auto Iter = FdDatas.find(EPollEvent.data.fd);
1941
0
    assuming(Iter != FdDatas.end());
1942
1943
0
    const bool NoInOut = !(EPollEvent.events & (EPOLLIN | EPOLLOUT));
1944
0
    if ((EPollEvent.events & EPOLLIN) ||
1945
0
        (NoInOut && EPollEvent.events & EPOLLHUP && Iter->second.ReadEvent)) {
1946
0
      assuming(Iter->second.ReadEvent);
1947
0
      assuming(Iter->second.ReadEvent->type == __WASI_EVENTTYPE_CLOCK ||
1948
0
               Iter->second.ReadEvent->type == __WASI_EVENTTYPE_FD_READ);
1949
0
      ProcessEvent(EPollEvent, *Iter->second.ReadEvent);
1950
0
    }
1951
0
    if (EPollEvent.events & EPOLLOUT ||
1952
0
        (NoInOut && EPollEvent.events & EPOLLHUP && Iter->second.WriteEvent)) {
1953
0
      assuming(Iter->second.WriteEvent);
1954
0
      assuming(Iter->second.WriteEvent->type == __WASI_EVENTTYPE_FD_WRITE);
1955
0
      ProcessEvent(EPollEvent, *Iter->second.WriteEvent);
1956
0
    }
1957
0
  }
1958
0
  for (auto &Timer : Timers) {
1959
    // Remove unused timer event, ignore failed.
1960
    // In kernel before 2.6.9, EPOLL_CTL_DEL required a non-null pointer. Use
1961
    // `this` as the dummy parameter.
1962
0
    ::epoll_ctl(Fd, EPOLL_CTL_DEL, Timer.Fd,
1963
0
                reinterpret_cast<struct epoll_event *>(this));
1964
0
    Ctx->releaseTimer(std::move(Timer));
1965
0
  }
1966
1967
0
  std::swap(FdDatas, OldFdDatas);
1968
0
  FdDatas.clear();
1969
0
  Timers.clear();
1970
0
  EPollEvents.clear();
1971
0
}
1972
1973
0
void Poller::reset() noexcept {
1974
0
  WasiEvents = {};
1975
0
  Events.clear();
1976
0
}
1977
1978
0
bool Poller::ok() noexcept { return FdHolder::ok(); }
1979
1980
} // namespace WASI
1981
} // namespace Host
1982
} // namespace WasmEdge
1983
1984
#endif