1 package wasi_snapshot_preview1
2
3 import (
4 "context"
5 "io"
6 "io/fs"
7 "math"
8 "path"
9 "strings"
10 "unsafe"
11
12 "github.com/tetratelabs/wazero/api"
13 experimentalsys "github.com/tetratelabs/wazero/experimental/sys"
14 socketapi "github.com/tetratelabs/wazero/internal/sock"
15 "github.com/tetratelabs/wazero/internal/sys"
16 "github.com/tetratelabs/wazero/internal/wasip1"
17 "github.com/tetratelabs/wazero/internal/wasm"
18 sysapi "github.com/tetratelabs/wazero/sys"
19 )
20
21
22
23
24
25 var fdAdvise = newHostFunc(
26 wasip1.FdAdviseName, fdAdviseFn,
27 []wasm.ValueType{i32, i64, i64, i32},
28 "fd", "offset", "len", "advice",
29 )
30
31 func fdAdviseFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
32 fd := int32(params[0])
33 _ = params[1]
34 _ = params[2]
35 advice := byte(params[3])
36 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
37
38 _, ok := fsc.LookupFile(fd)
39 if !ok {
40 return experimentalsys.EBADF
41 }
42
43 switch advice {
44 case wasip1.FdAdviceNormal,
45 wasip1.FdAdviceSequential,
46 wasip1.FdAdviceRandom,
47 wasip1.FdAdviceWillNeed,
48 wasip1.FdAdviceDontNeed,
49 wasip1.FdAdviceNoReuse:
50 default:
51 return experimentalsys.EINVAL
52 }
53
54
55
56
57
58
59
60
61 return 0
62 }
63
64
65
66
67
68 var fdAllocate = newHostFunc(
69 wasip1.FdAllocateName, fdAllocateFn,
70 []wasm.ValueType{i32, i64, i64},
71 "fd", "offset", "len",
72 )
73
74 func fdAllocateFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
75 fd := int32(params[0])
76 offset := params[1]
77 length := params[2]
78
79 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
80 f, ok := fsc.LookupFile(fd)
81 if !ok {
82 return experimentalsys.EBADF
83 }
84
85 tail := int64(offset + length)
86 if tail < 0 {
87 return experimentalsys.EINVAL
88 }
89
90 st, errno := f.File.Stat()
91 if errno != 0 {
92 return errno
93 }
94
95 if st.Size >= tail {
96 return 0
97 }
98
99 return f.File.Truncate(tail)
100 }
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118 var fdClose = newHostFunc(wasip1.FdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
119
120 func fdCloseFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
121 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
122 fd := int32(params[0])
123
124 return fsc.CloseFile(fd)
125 }
126
127
128
129
130
131 var fdDatasync = newHostFunc(wasip1.FdDatasyncName, fdDatasyncFn, []api.ValueType{i32}, "fd")
132
133 func fdDatasyncFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
134 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
135 fd := int32(params[0])
136
137
138 if f, ok := fsc.LookupFile(fd); !ok {
139 return experimentalsys.EBADF
140 } else {
141 return f.File.Datasync()
142 }
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182 var fdFdstatGet = newHostFunc(wasip1.FdFdstatGetName, fdFdstatGetFn, []api.ValueType{i32, i32}, "fd", "result.stat")
183
184
185
186 func fdFdstatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
187 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
188
189 fd, resultFdstat := int32(params[0]), uint32(params[1])
190
191
192 buf, ok := mod.Memory().Read(resultFdstat, 24)
193 if !ok {
194 return experimentalsys.EFAULT
195 }
196
197 var fdflags uint16
198 var st sysapi.Stat_t
199 var errno experimentalsys.Errno
200 f, ok := fsc.LookupFile(fd)
201 if !ok {
202 return experimentalsys.EBADF
203 } else if st, errno = f.File.Stat(); errno != 0 {
204 return errno
205 } else if f.File.IsAppend() {
206 fdflags |= wasip1.FD_APPEND
207 }
208
209 if f.File.IsNonblock() {
210 fdflags |= wasip1.FD_NONBLOCK
211 }
212
213 var fsRightsBase uint32
214 var fsRightsInheriting uint32
215 fileType := getExtendedWasiFiletype(f.File, st.Mode)
216
217 switch fileType {
218 case wasip1.FILETYPE_DIRECTORY:
219
220
221 fsRightsBase = dirRightsBase
222 fsRightsInheriting = fileRightsBase | dirRightsBase
223 case wasip1.FILETYPE_CHARACTER_DEVICE:
224
225
226
227 fsRightsBase = fileRightsBase &^ wasip1.RIGHT_FD_SEEK &^ wasip1.RIGHT_FD_TELL
228 default:
229 fsRightsBase = fileRightsBase
230 }
231
232 writeFdstat(buf, fileType, fdflags, fsRightsBase, fsRightsInheriting)
233 return 0
234 }
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249 func isPreopenedStdio(fd int32, f *sys.FileEntry) bool {
250 return fd <= sys.FdStderr && f.IsPreopen
251 }
252
253 const fileRightsBase = wasip1.RIGHT_FD_DATASYNC |
254 wasip1.RIGHT_FD_READ |
255 wasip1.RIGHT_FD_SEEK |
256 wasip1.RIGHT_FDSTAT_SET_FLAGS |
257 wasip1.RIGHT_FD_SYNC |
258 wasip1.RIGHT_FD_TELL |
259 wasip1.RIGHT_FD_WRITE |
260 wasip1.RIGHT_FD_ADVISE |
261 wasip1.RIGHT_FD_ALLOCATE |
262 wasip1.RIGHT_FD_FILESTAT_GET |
263 wasip1.RIGHT_FD_FILESTAT_SET_SIZE |
264 wasip1.RIGHT_FD_FILESTAT_SET_TIMES |
265 wasip1.RIGHT_POLL_FD_READWRITE
266
267 const dirRightsBase = wasip1.RIGHT_FD_DATASYNC |
268 wasip1.RIGHT_FDSTAT_SET_FLAGS |
269 wasip1.RIGHT_FD_SYNC |
270 wasip1.RIGHT_PATH_CREATE_DIRECTORY |
271 wasip1.RIGHT_PATH_CREATE_FILE |
272 wasip1.RIGHT_PATH_LINK_SOURCE |
273 wasip1.RIGHT_PATH_LINK_TARGET |
274 wasip1.RIGHT_PATH_OPEN |
275 wasip1.RIGHT_FD_READDIR |
276 wasip1.RIGHT_PATH_READLINK |
277 wasip1.RIGHT_PATH_RENAME_SOURCE |
278 wasip1.RIGHT_PATH_RENAME_TARGET |
279 wasip1.RIGHT_PATH_FILESTAT_GET |
280 wasip1.RIGHT_PATH_FILESTAT_SET_SIZE |
281 wasip1.RIGHT_PATH_FILESTAT_SET_TIMES |
282 wasip1.RIGHT_FD_FILESTAT_GET |
283 wasip1.RIGHT_FD_FILESTAT_SET_TIMES |
284 wasip1.RIGHT_PATH_SYMLINK |
285 wasip1.RIGHT_PATH_REMOVE_DIRECTORY |
286 wasip1.RIGHT_PATH_UNLINK_FILE
287
288 func writeFdstat(buf []byte, fileType uint8, fdflags uint16, fsRightsBase, fsRightsInheriting uint32) {
289 b := (*[24]byte)(buf)
290 le.PutUint16(b[0:], uint16(fileType))
291 le.PutUint16(b[2:], fdflags)
292 le.PutUint32(b[4:], 0)
293 le.PutUint64(b[8:], uint64(fsRightsBase))
294 le.PutUint64(b[16:], uint64(fsRightsInheriting))
295 }
296
297
298
299 var fdFdstatSetFlags = newHostFunc(wasip1.FdFdstatSetFlagsName, fdFdstatSetFlagsFn, []wasm.ValueType{i32, i32}, "fd", "flags")
300
301 func fdFdstatSetFlagsFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
302 fd, wasiFlag := int32(params[0]), uint16(params[1])
303 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
304
305
306 if wasip1.FD_DSYNC&wasiFlag != 0 || wasip1.FD_RSYNC&wasiFlag != 0 || wasip1.FD_SYNC&wasiFlag != 0 {
307 return experimentalsys.EINVAL
308 }
309
310 if f, ok := fsc.LookupFile(fd); !ok {
311 return experimentalsys.EBADF
312 } else {
313 nonblock := wasip1.FD_NONBLOCK&wasiFlag != 0
314 errno := f.File.SetNonblock(nonblock)
315 if errno != 0 {
316 return errno
317 }
318 if stat, err := f.File.Stat(); err == 0 && stat.Mode.IsRegular() {
319
320 append := wasip1.FD_APPEND&wasiFlag != 0
321 return f.File.SetAppend(append)
322 }
323 }
324
325 return 0
326 }
327
328
329
330
331 var fdFdstatSetRights = stubFunction(
332 wasip1.FdFdstatSetRightsName,
333 []wasm.ValueType{i32, i64, i64},
334 "fd", "fs_rights_base", "fs_rights_inheriting",
335 )
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384 var fdFilestatGet = newHostFunc(wasip1.FdFilestatGetName, fdFilestatGetFn, []api.ValueType{i32, i32}, "fd", "result.filestat")
385
386
387
388 func fdFilestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
389 return fdFilestatGetFunc(mod, int32(params[0]), uint32(params[1]))
390 }
391
392 func fdFilestatGetFunc(mod api.Module, fd int32, resultBuf uint32) experimentalsys.Errno {
393 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
394
395
396 buf, ok := mod.Memory().Read(resultBuf, 64)
397 if !ok {
398 return experimentalsys.EFAULT
399 }
400
401 f, ok := fsc.LookupFile(fd)
402 if !ok {
403 return experimentalsys.EBADF
404 }
405
406 st, errno := f.File.Stat()
407 if errno != 0 {
408 return errno
409 }
410
411 filetype := getExtendedWasiFiletype(f.File, st.Mode)
412 return writeFilestat(buf, &st, filetype)
413 }
414
415 func getExtendedWasiFiletype(file experimentalsys.File, fm fs.FileMode) (ftype uint8) {
416 ftype = getWasiFiletype(fm)
417 if ftype == wasip1.FILETYPE_UNKNOWN {
418 if _, ok := file.(socketapi.TCPSock); ok {
419 ftype = wasip1.FILETYPE_SOCKET_STREAM
420 } else if _, ok = file.(socketapi.TCPConn); ok {
421 ftype = wasip1.FILETYPE_SOCKET_STREAM
422 }
423 }
424 return
425 }
426
427 func getWasiFiletype(fm fs.FileMode) uint8 {
428 switch {
429 case fm.IsRegular():
430 return wasip1.FILETYPE_REGULAR_FILE
431 case fm.IsDir():
432 return wasip1.FILETYPE_DIRECTORY
433 case fm&fs.ModeSymlink != 0:
434 return wasip1.FILETYPE_SYMBOLIC_LINK
435 case fm&fs.ModeDevice != 0:
436
437
438 if fm&fs.ModeCharDevice != 0 {
439 return wasip1.FILETYPE_CHARACTER_DEVICE
440 }
441 return wasip1.FILETYPE_BLOCK_DEVICE
442 default:
443 return wasip1.FILETYPE_UNKNOWN
444 }
445 }
446
447 func writeFilestat(buf []byte, st *sysapi.Stat_t, ftype uint8) (errno experimentalsys.Errno) {
448 le.PutUint64(buf, st.Dev)
449 le.PutUint64(buf[8:], st.Ino)
450 le.PutUint64(buf[16:], uint64(ftype))
451 le.PutUint64(buf[24:], st.Nlink)
452 le.PutUint64(buf[32:], uint64(st.Size))
453 le.PutUint64(buf[40:], uint64(st.Atim))
454 le.PutUint64(buf[48:], uint64(st.Mtim))
455 le.PutUint64(buf[56:], uint64(st.Ctim))
456 return
457 }
458
459
460
461
462
463 var fdFilestatSetSize = newHostFunc(wasip1.FdFilestatSetSizeName, fdFilestatSetSizeFn, []wasm.ValueType{i32, i64}, "fd", "size")
464
465 func fdFilestatSetSizeFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
466 fd := int32(params[0])
467 size := int64(params[1])
468
469 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
470
471
472 if f, ok := fsc.LookupFile(fd); !ok {
473 return experimentalsys.EBADF
474 } else {
475 return f.File.Truncate(size)
476 }
477 }
478
479
480
481
482
483 var fdFilestatSetTimes = newHostFunc(
484 wasip1.FdFilestatSetTimesName, fdFilestatSetTimesFn,
485 []wasm.ValueType{i32, i64, i64, i32},
486 "fd", "atim", "mtim", "fst_flags",
487 )
488
489 func fdFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
490 fd := int32(params[0])
491 atim := int64(params[1])
492 mtim := int64(params[2])
493 fstFlags := uint16(params[3])
494
495 sys := mod.(*wasm.ModuleInstance).Sys
496 fsc := sys.FS()
497
498 f, ok := fsc.LookupFile(fd)
499 if !ok {
500 return experimentalsys.EBADF
501 }
502
503 atim, mtim, errno := toTimes(sys.WalltimeNanos, atim, mtim, fstFlags)
504 if errno != 0 {
505 return errno
506 }
507
508
509 errno = f.File.Utimens(atim, mtim)
510
511
512 switch errno {
513 case experimentalsys.EPERM, experimentalsys.ENOSYS:
514 errno = f.FS.Utimens(f.Name, atim, mtim)
515 }
516
517 return errno
518 }
519
520 func toTimes(walltime func() int64, atim, mtim int64, fstFlags uint16) (int64, int64, experimentalsys.Errno) {
521
522
523 var nowTim int64
524
525
526 if set, now := fstFlags&wasip1.FstflagsAtim != 0, fstFlags&wasip1.FstflagsAtimNow != 0; set && now {
527 return 0, 0, experimentalsys.EINVAL
528 } else if set {
529
530 } else if now {
531 nowTim = walltime()
532 atim = nowTim
533 } else {
534 atim = experimentalsys.UTIME_OMIT
535 }
536
537
538 if set, now := fstFlags&wasip1.FstflagsMtim != 0, fstFlags&wasip1.FstflagsMtimNow != 0; set && now {
539 return 0, 0, experimentalsys.EINVAL
540 } else if set {
541
542 } else if now {
543 if nowTim != 0 {
544 mtim = nowTim
545 } else {
546 mtim = walltime()
547 }
548 } else {
549 mtim = experimentalsys.UTIME_OMIT
550 }
551 return atim, mtim, 0
552 }
553
554
555
556
557
558
559
560 var fdPread = newHostFunc(
561 wasip1.FdPreadName, fdPreadFn,
562 []api.ValueType{i32, i32, i32, i64, i32},
563 "fd", "iovs", "iovs_len", "offset", "result.nread",
564 )
565
566 func fdPreadFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
567 return fdReadOrPread(mod, params, true)
568 }
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601 var fdPrestatGet = newHostFunc(wasip1.FdPrestatGetName, fdPrestatGetFn, []api.ValueType{i32, i32}, "fd", "result.prestat")
602
603 func fdPrestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
604 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
605 fd, resultPrestat := int32(params[0]), uint32(params[1])
606
607 name, errno := preopenPath(fsc, fd)
608 if errno != 0 {
609 return errno
610 }
611
612
613
614 prestat := uint64(len(name) << 32)
615 if !mod.Memory().WriteUint64Le(resultPrestat, prestat) {
616 return experimentalsys.EFAULT
617 }
618 return 0
619 }
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651 var fdPrestatDirName = newHostFunc(
652 wasip1.FdPrestatDirNameName, fdPrestatDirNameFn,
653 []api.ValueType{i32, i32, i32},
654 "fd", "result.path", "result.path_len",
655 )
656
657 func fdPrestatDirNameFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
658 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
659 fd, path, pathLen := int32(params[0]), uint32(params[1]), uint32(params[2])
660
661 name, errno := preopenPath(fsc, fd)
662 if errno != 0 {
663 return errno
664 }
665
666
667 if uint32(len(name)) < pathLen {
668 return experimentalsys.ENAMETOOLONG
669 }
670
671 if !mod.Memory().Write(path, []byte(name)[:pathLen]) {
672 return experimentalsys.EFAULT
673 }
674 return 0
675 }
676
677
678
679
680
681
682
683 var fdPwrite = newHostFunc(
684 wasip1.FdPwriteName, fdPwriteFn,
685 []api.ValueType{i32, i32, i32, i64, i32},
686 "fd", "iovs", "iovs_len", "offset", "result.nwritten",
687 )
688
689 func fdPwriteFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
690 return fdWriteOrPwrite(mod, params, true)
691 }
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742 var fdRead = newHostFunc(
743 wasip1.FdReadName, fdReadFn,
744 []api.ValueType{i32, i32, i32, i32},
745 "fd", "iovs", "iovs_len", "result.nread",
746 )
747
748
749 type preader struct {
750 f experimentalsys.File
751 offset int64
752 }
753
754
755 func (w *preader) Read(buf []byte) (n int, errno experimentalsys.Errno) {
756 if len(buf) == 0 {
757 return 0, 0
758 }
759
760 n, err := w.f.Pread(buf, w.offset)
761 w.offset += int64(n)
762 return n, err
763 }
764
765 func fdReadFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
766 return fdReadOrPread(mod, params, false)
767 }
768
769 func fdReadOrPread(mod api.Module, params []uint64, isPread bool) experimentalsys.Errno {
770 mem := mod.Memory()
771 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
772
773 fd := int32(params[0])
774 iovs := uint32(params[1])
775 iovsCount := uint32(params[2])
776
777 var resultNread uint32
778 var reader func(buf []byte) (n int, errno experimentalsys.Errno)
779 if f, ok := fsc.LookupFile(fd); !ok {
780 return experimentalsys.EBADF
781 } else if isPread {
782 offset := int64(params[3])
783 reader = (&preader{f: f.File, offset: offset}).Read
784 resultNread = uint32(params[4])
785 } else {
786 reader = f.File.Read
787 resultNread = uint32(params[3])
788 }
789
790 nread, errno := readv(mem, iovs, iovsCount, reader)
791 if errno != 0 {
792 return errno
793 }
794 if !mem.WriteUint32Le(resultNread, nread) {
795 return experimentalsys.EFAULT
796 } else {
797 return 0
798 }
799 }
800
801 func readv(mem api.Memory, iovs uint32, iovsCount uint32, reader func(buf []byte) (nread int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
802 var nread uint32
803 iovsStop := iovsCount << 3
804 iovsBuf, ok := mem.Read(iovs, iovsStop)
805 if !ok {
806 return 0, experimentalsys.EFAULT
807 }
808
809 for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
810 offset := le.Uint32(iovsBuf[iovsPos:])
811 l := le.Uint32(iovsBuf[iovsPos+4:])
812
813 if l == 0 {
814 continue
815 }
816
817 b, ok := mem.Read(offset, l)
818 if !ok {
819 return 0, experimentalsys.EFAULT
820 }
821
822 n, errno := reader(b)
823 nread += uint32(n)
824
825 if errno == experimentalsys.ENOSYS {
826 return 0, experimentalsys.EBADF
827 } else if errno != 0 {
828 return 0, errno
829 } else if n < int(l) {
830 break
831 }
832 }
833 return nread, 0
834 }
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856 var fdReaddir = newHostFunc(
857 wasip1.FdReaddirName, fdReaddirFn,
858 []wasm.ValueType{i32, i32, i32, i64, i32},
859 "fd", "buf", "buf_len", "cookie", "result.bufused",
860 )
861
862 func fdReaddirFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
863 mem := mod.Memory()
864 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
865
866 fd := int32(params[0])
867 buf := uint32(params[1])
868 bufLen := uint32(params[2])
869 cookie := params[3]
870 resultBufused := uint32(params[4])
871
872
873 if bufLen < wasip1.DirentSize {
874
875
876 return experimentalsys.EINVAL
877 }
878
879
880 dir, errno := direntCache(fsc, fd)
881 if errno != 0 {
882 return errno
883 }
884
885
886
887
888
889 maxDirEntries := bufLen/wasip1.DirentSize + 1
890
891
892
893
894
895
896 maxDirEntries += 1
897
898
899
900
901
902 dirents, errno := dir.Read(cookie, maxDirEntries)
903 if errno != 0 {
904 return errno
905 }
906
907
908
909 bufToWrite, direntCount, truncatedLen := maxDirents(dirents, bufLen)
910
911
912 if bufToWrite > 0 {
913
914
915
916 d_next := cookie + 1
917
918
919
920 buf, ok := mem.Read(buf, bufToWrite)
921 if !ok {
922 return experimentalsys.EFAULT
923 }
924
925 writeDirents(buf, dirents, d_next, direntCount, truncatedLen)
926 }
927
928
929
930 bufused := bufToWrite
931 if truncatedLen > 0 {
932 bufused = bufLen
933 }
934
935 if !mem.WriteUint32Le(resultBufused, bufused) {
936 return experimentalsys.EFAULT
937 }
938 return 0
939 }
940
941 const largestDirent = int64(math.MaxUint32 - wasip1.DirentSize)
942
943
944
945
946
947 func maxDirents(dirents []experimentalsys.Dirent, bufLen uint32) (bufToWrite uint32, direntCount int, truncatedLen uint32) {
948 lenRemaining := bufLen
949 for i := range dirents {
950 if lenRemaining == 0 {
951 break
952 }
953 d := dirents[i]
954 direntCount++
955
956
957 nameLen := int64(len(d.Name))
958 var entryLen uint32
959
960
961
962 if el := int64(wasip1.DirentSize) + nameLen; el < 0 || el > largestDirent {
963
964
965 panic("invalid filename: too large")
966 } else {
967 entryLen = uint32(el)
968 }
969
970 if entryLen > lenRemaining {
971
972
973
974
975
976
977 if lenRemaining >= wasip1.DirentSize {
978 truncatedLen = wasip1.DirentSize
979 } else {
980 truncatedLen = lenRemaining
981 }
982 bufToWrite += truncatedLen
983 break
984 }
985
986
987 lenRemaining -= entryLen
988 bufToWrite += entryLen
989 }
990 return
991 }
992
993
994
995
996 func writeDirents(buf []byte, dirents []experimentalsys.Dirent, d_next uint64, direntCount int, truncatedLen uint32) {
997 pos := uint32(0)
998 skipNameI := -1
999
1000
1001
1002 if truncatedLen > 0 {
1003 if truncatedLen < wasip1.DirentSize {
1004 direntCount--
1005 } else {
1006 skipNameI = direntCount - 1
1007 }
1008 }
1009
1010 for i := 0; i < direntCount; i++ {
1011 e := dirents[i]
1012 nameLen := uint32(len(e.Name))
1013 writeDirent(buf[pos:], d_next, e.Ino, nameLen, e.Type)
1014 d_next++
1015 pos += wasip1.DirentSize
1016
1017 if i != skipNameI {
1018 copy(buf[pos:], e.Name)
1019 pos += nameLen
1020 }
1021 }
1022 }
1023
1024
1025 func writeDirent(buf []byte, dNext uint64, ino sysapi.Inode, dNamlen uint32, dType fs.FileMode) {
1026 le.PutUint64(buf, dNext)
1027 le.PutUint64(buf[8:], ino)
1028 le.PutUint32(buf[16:], dNamlen)
1029 filetype := getWasiFiletype(dType)
1030 le.PutUint32(buf[20:], uint32(filetype))
1031 }
1032
1033
1034
1035 func direntCache(fsc *sys.FSContext, fd int32) (*sys.DirentCache, experimentalsys.Errno) {
1036 if f, ok := fsc.LookupFile(fd); !ok {
1037 return nil, experimentalsys.EBADF
1038 } else if dir, errno := f.DirentCache(); errno == 0 {
1039 return dir, 0
1040 } else if errno == experimentalsys.ENOTDIR {
1041
1042
1043
1044
1045
1046
1047 return nil, experimentalsys.EBADF
1048 } else {
1049 return nil, errno
1050 }
1051 }
1052
1053
1054
1055
1056
1057 var fdRenumber = newHostFunc(wasip1.FdRenumberName, fdRenumberFn, []wasm.ValueType{i32, i32}, "fd", "to")
1058
1059 func fdRenumberFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1060 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1061
1062 from := int32(params[0])
1063 to := int32(params[1])
1064
1065 if errno := fsc.Renumber(from, to); errno != 0 {
1066 return errno
1067 }
1068 return 0
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109 var fdSeek = newHostFunc(
1110 wasip1.FdSeekName, fdSeekFn,
1111 []api.ValueType{i32, i64, i32, i32},
1112 "fd", "offset", "whence", "result.newoffset",
1113 )
1114
1115 func fdSeekFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1116 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1117 fd := int32(params[0])
1118 offset := params[1]
1119 whence := uint32(params[2])
1120 resultNewoffset := uint32(params[3])
1121
1122 if f, ok := fsc.LookupFile(fd); !ok {
1123 return experimentalsys.EBADF
1124 } else if isDir, _ := f.File.IsDir(); isDir {
1125 return experimentalsys.EISDIR
1126 } else if newOffset, errno := f.File.Seek(int64(offset), int(whence)); errno != 0 {
1127 return errno
1128 } else if !mod.Memory().WriteUint64Le(resultNewoffset, uint64(newOffset)) {
1129 return experimentalsys.EFAULT
1130 }
1131 return 0
1132 }
1133
1134
1135
1136
1137
1138 var fdSync = newHostFunc(wasip1.FdSyncName, fdSyncFn, []api.ValueType{i32}, "fd")
1139
1140 func fdSyncFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1141 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1142 fd := int32(params[0])
1143
1144
1145 if f, ok := fsc.LookupFile(fd); !ok {
1146 return experimentalsys.EBADF
1147 } else {
1148 return f.File.Sync()
1149 }
1150 }
1151
1152
1153
1154
1155
1156 var fdTell = newHostFunc(wasip1.FdTellName, fdTellFn, []api.ValueType{i32, i32}, "fd", "result.offset")
1157
1158 func fdTellFn(ctx context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1159 fd := params[0]
1160 offset := uint64(0)
1161 whence := uint64(io.SeekCurrent)
1162 resultNewoffset := params[1]
1163
1164 fdSeekParams := []uint64{fd, offset, whence, resultNewoffset}
1165 return fdSeekFn(ctx, mod, fdSeekParams)
1166 }
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226 var fdWrite = newHostFunc(
1227 wasip1.FdWriteName, fdWriteFn,
1228 []api.ValueType{i32, i32, i32, i32},
1229 "fd", "iovs", "iovs_len", "result.nwritten",
1230 )
1231
1232 func fdWriteFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1233 return fdWriteOrPwrite(mod, params, false)
1234 }
1235
1236
1237 type pwriter struct {
1238 f experimentalsys.File
1239 offset int64
1240 }
1241
1242
1243 func (w *pwriter) Write(buf []byte) (n int, errno experimentalsys.Errno) {
1244 if len(buf) == 0 {
1245 return 0, 0
1246 }
1247
1248 n, err := w.f.Pwrite(buf, w.offset)
1249 w.offset += int64(n)
1250 return n, err
1251 }
1252
1253 func fdWriteOrPwrite(mod api.Module, params []uint64, isPwrite bool) experimentalsys.Errno {
1254 mem := mod.Memory()
1255 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1256
1257 fd := int32(params[0])
1258 iovs := uint32(params[1])
1259 iovsCount := uint32(params[2])
1260
1261 var resultNwritten uint32
1262 var writer func(buf []byte) (n int, errno experimentalsys.Errno)
1263 if f, ok := fsc.LookupFile(fd); !ok {
1264 return experimentalsys.EBADF
1265 } else if isPwrite {
1266 offset := int64(params[3])
1267 writer = (&pwriter{f: f.File, offset: offset}).Write
1268 resultNwritten = uint32(params[4])
1269 } else {
1270 writer = f.File.Write
1271 resultNwritten = uint32(params[3])
1272 }
1273
1274 nwritten, errno := writev(mem, iovs, iovsCount, writer)
1275 if errno != 0 {
1276 return errno
1277 }
1278
1279 if !mod.Memory().WriteUint32Le(resultNwritten, nwritten) {
1280 return experimentalsys.EFAULT
1281 }
1282 return 0
1283 }
1284
1285 func writev(mem api.Memory, iovs uint32, iovsCount uint32, writer func(buf []byte) (n int, errno experimentalsys.Errno)) (uint32, experimentalsys.Errno) {
1286 var nwritten uint32
1287 iovsStop := iovsCount << 3
1288 iovsBuf, ok := mem.Read(iovs, iovsStop)
1289 if !ok {
1290 return 0, experimentalsys.EFAULT
1291 }
1292
1293 for iovsPos := uint32(0); iovsPos < iovsStop; iovsPos += 8 {
1294 offset := le.Uint32(iovsBuf[iovsPos:])
1295 l := le.Uint32(iovsBuf[iovsPos+4:])
1296
1297 b, ok := mem.Read(offset, l)
1298 if !ok {
1299 return 0, experimentalsys.EFAULT
1300 }
1301 n, errno := writer(b)
1302 nwritten += uint32(n)
1303 if errno == experimentalsys.ENOSYS {
1304 return 0, experimentalsys.EBADF
1305 } else if errno != 0 {
1306 return 0, errno
1307 }
1308 }
1309 return nwritten, 0
1310 }
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333 var pathCreateDirectory = newHostFunc(
1334 wasip1.PathCreateDirectoryName, pathCreateDirectoryFn,
1335 []wasm.ValueType{i32, i32, i32},
1336 "fd", "path", "path_len",
1337 )
1338
1339 func pathCreateDirectoryFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1340 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1341
1342 fd := int32(params[0])
1343 path := uint32(params[1])
1344 pathLen := uint32(params[2])
1345
1346 preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
1347 if errno != 0 {
1348 return errno
1349 }
1350
1351 if errno = preopen.Mkdir(pathName, 0o700); errno != 0 {
1352 return errno
1353 }
1354
1355 return 0
1356 }
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386 var pathFilestatGet = newHostFunc(
1387 wasip1.PathFilestatGetName, pathFilestatGetFn,
1388 []api.ValueType{i32, i32, i32, i32, i32},
1389 "fd", "flags", "path", "path_len", "result.filestat",
1390 )
1391
1392 func pathFilestatGetFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1393 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1394
1395 fd := int32(params[0])
1396 flags := uint16(params[1])
1397 path := uint32(params[2])
1398 pathLen := uint32(params[3])
1399
1400 preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
1401 if errno != 0 {
1402 return errno
1403 }
1404
1405
1406 var st sysapi.Stat_t
1407
1408 if (flags & wasip1.LOOKUP_SYMLINK_FOLLOW) == 0 {
1409 st, errno = preopen.Lstat(pathName)
1410 } else {
1411 st, errno = preopen.Stat(pathName)
1412 }
1413 if errno != 0 {
1414 return errno
1415 }
1416
1417
1418 resultBuf := uint32(params[4])
1419 buf, ok := mod.Memory().Read(resultBuf, 64)
1420 if !ok {
1421 return experimentalsys.EFAULT
1422 }
1423
1424 filetype := getWasiFiletype(st.Mode)
1425 return writeFilestat(buf, &st, filetype)
1426 }
1427
1428
1429
1430
1431
1432 var pathFilestatSetTimes = newHostFunc(
1433 wasip1.PathFilestatSetTimesName, pathFilestatSetTimesFn,
1434 []wasm.ValueType{i32, i32, i32, i32, i64, i64, i32},
1435 "fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags",
1436 )
1437
1438 func pathFilestatSetTimesFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1439 fd := int32(params[0])
1440 flags := uint16(params[1])
1441 path := uint32(params[2])
1442 pathLen := uint32(params[3])
1443 atim := int64(params[4])
1444 mtim := int64(params[5])
1445 fstFlags := uint16(params[6])
1446
1447 sys := mod.(*wasm.ModuleInstance).Sys
1448 fsc := sys.FS()
1449
1450 atim, mtim, errno := toTimes(sys.WalltimeNanos, atim, mtim, fstFlags)
1451 if errno != 0 {
1452 return errno
1453 }
1454
1455 preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
1456 if errno != 0 {
1457 return errno
1458 }
1459
1460 symlinkFollow := flags&wasip1.LOOKUP_SYMLINK_FOLLOW != 0
1461 if symlinkFollow {
1462 return preopen.Utimens(pathName, atim, mtim)
1463 }
1464
1465 if f, errno := preopen.OpenFile(pathName, experimentalsys.O_WRONLY, 0); errno != 0 {
1466 return errno
1467 } else {
1468 defer f.Close()
1469 return f.Utimens(atim, mtim)
1470 }
1471 }
1472
1473
1474
1475
1476
1477 var pathLink = newHostFunc(
1478 wasip1.PathLinkName, pathLinkFn,
1479 []wasm.ValueType{i32, i32, i32, i32, i32, i32, i32},
1480 "old_fd", "old_flags", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
1481 )
1482
1483 func pathLinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1484 mem := mod.Memory()
1485 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1486
1487 oldFD := int32(params[0])
1488
1489 _ = uint32(params[1])
1490 oldPath := uint32(params[2])
1491 oldPathLen := uint32(params[3])
1492
1493 oldFS, oldName, errno := atPath(fsc, mem, oldFD, oldPath, oldPathLen)
1494 if errno != 0 {
1495 return errno
1496 }
1497
1498 newFD := int32(params[4])
1499 newPath := uint32(params[5])
1500 newPathLen := uint32(params[6])
1501
1502 newFS, newName, errno := atPath(fsc, mem, newFD, newPath, newPathLen)
1503 if errno != 0 {
1504 return errno
1505 }
1506
1507 if oldFS != newFS {
1508 return experimentalsys.ENOSYS
1509 }
1510
1511 return oldFS.Link(oldName, newName)
1512 }
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567 var pathOpen = newHostFunc(
1568 wasip1.PathOpenName, pathOpenFn,
1569 []api.ValueType{i32, i32, i32, i32, i32, i64, i64, i32, i32},
1570 "fd", "dirflags", "path", "path_len", "oflags", "fs_rights_base", "fs_rights_inheriting", "fdflags", "result.opened_fd",
1571 )
1572
1573 func pathOpenFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1574 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1575
1576 preopenFD := int32(params[0])
1577
1578
1579
1580 dirflags := uint16(params[1])
1581
1582 path := uint32(params[2])
1583 pathLen := uint32(params[3])
1584
1585 oflags := uint16(params[4])
1586
1587 rights := uint32(params[5])
1588
1589 _ = params[6]
1590
1591 fdflags := uint16(params[7])
1592 resultOpenedFD := uint32(params[8])
1593
1594 preopen, pathName, errno := atPath(fsc, mod.Memory(), preopenFD, path, pathLen)
1595 if errno != 0 {
1596 return errno
1597 }
1598
1599 fileOpenFlags := openFlags(dirflags, oflags, fdflags, rights)
1600 isDir := fileOpenFlags&experimentalsys.O_DIRECTORY != 0
1601
1602 if isDir && oflags&wasip1.O_CREAT != 0 {
1603 return experimentalsys.EINVAL
1604 }
1605
1606 newFD, errno := fsc.OpenFile(preopen, pathName, fileOpenFlags, 0o600)
1607 if errno != 0 {
1608 return errno
1609 }
1610
1611
1612 if isDir {
1613 if f, ok := fsc.LookupFile(newFD); !ok {
1614 return experimentalsys.EBADF
1615 } else if isDir, errno := f.File.IsDir(); errno != 0 {
1616 _ = fsc.CloseFile(newFD)
1617 return errno
1618 } else if !isDir {
1619 _ = fsc.CloseFile(newFD)
1620 return experimentalsys.ENOTDIR
1621 }
1622 }
1623
1624 if !mod.Memory().WriteUint32Le(resultOpenedFD, uint32(newFD)) {
1625 _ = fsc.CloseFile(newFD)
1626 return experimentalsys.EFAULT
1627 }
1628 return 0
1629 }
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647 func atPath(fsc *sys.FSContext, mem api.Memory, fd int32, p, pathLen uint32) (experimentalsys.FS, string, experimentalsys.Errno) {
1648 b, ok := mem.Read(p, pathLen)
1649 if !ok {
1650 return nil, "", experimentalsys.EFAULT
1651 }
1652 pathName := string(b)
1653
1654
1655
1656 hasTrailingSlash := strings.HasSuffix(pathName, "/")
1657
1658
1659
1660 pathName = path.Clean(pathName)
1661
1662
1663
1664 if !fs.ValidPath(pathName) {
1665 return nil, "", experimentalsys.EPERM
1666 }
1667
1668
1669 if hasTrailingSlash {
1670 pathName = pathName + "/"
1671 }
1672
1673 if f, ok := fsc.LookupFile(fd); !ok {
1674 return nil, "", experimentalsys.EBADF
1675 } else if isDir, errno := f.File.IsDir(); errno != 0 {
1676 return nil, "", errno
1677 } else if !isDir {
1678 return nil, "", experimentalsys.ENOTDIR
1679 } else if f.IsPreopen {
1680 return f.FS, pathName, 0
1681 } else {
1682
1683 return f.FS, f.Name + "/" + pathName, 0
1684 }
1685 }
1686
1687 func preopenPath(fsc *sys.FSContext, fd int32) (string, experimentalsys.Errno) {
1688 if f, ok := fsc.LookupFile(fd); !ok {
1689 return "", experimentalsys.EBADF
1690 } else if !f.IsPreopen {
1691 return "", experimentalsys.EBADF
1692 } else if isDir, errno := f.File.IsDir(); errno != 0 || !isDir {
1693
1694
1695 return "", errno
1696 } else {
1697 return f.Name, 0
1698 }
1699 }
1700
1701 func openFlags(dirflags, oflags, fdflags uint16, rights uint32) (openFlags experimentalsys.Oflag) {
1702 if dirflags&wasip1.LOOKUP_SYMLINK_FOLLOW == 0 {
1703 openFlags |= experimentalsys.O_NOFOLLOW
1704 }
1705 if oflags&wasip1.O_DIRECTORY != 0 {
1706 openFlags |= experimentalsys.O_DIRECTORY
1707 return
1708 } else if oflags&wasip1.O_EXCL != 0 {
1709 openFlags |= experimentalsys.O_EXCL
1710 }
1711
1712
1713
1714
1715
1716
1717
1718 defaultMode := experimentalsys.O_RDONLY
1719 if oflags&wasip1.O_TRUNC != 0 {
1720 openFlags |= experimentalsys.O_TRUNC
1721 defaultMode = experimentalsys.O_RDWR
1722 }
1723 if oflags&wasip1.O_CREAT != 0 {
1724 openFlags |= experimentalsys.O_CREAT
1725 defaultMode = experimentalsys.O_RDWR
1726 }
1727 if fdflags&wasip1.FD_NONBLOCK != 0 {
1728 openFlags |= experimentalsys.O_NONBLOCK
1729 }
1730 if fdflags&wasip1.FD_APPEND != 0 {
1731 openFlags |= experimentalsys.O_APPEND
1732 defaultMode = experimentalsys.O_RDWR
1733 }
1734 if fdflags&wasip1.FD_DSYNC != 0 {
1735 openFlags |= experimentalsys.O_DSYNC
1736 }
1737 if fdflags&wasip1.FD_RSYNC != 0 {
1738 openFlags |= experimentalsys.O_RSYNC
1739 }
1740 if fdflags&wasip1.FD_SYNC != 0 {
1741 openFlags |= experimentalsys.O_SYNC
1742 }
1743
1744
1745
1746
1747
1748 const r = wasip1.RIGHT_FD_READ
1749 const w = wasip1.RIGHT_FD_WRITE
1750 const rw = r | w
1751 switch {
1752 case (rights & rw) == rw:
1753 openFlags |= experimentalsys.O_RDWR
1754 case (rights & w) == w:
1755 openFlags |= experimentalsys.O_WRONLY
1756 case (rights & r) == r:
1757 openFlags |= experimentalsys.O_RDONLY
1758 default:
1759 openFlags |= defaultMode
1760 }
1761 return
1762 }
1763
1764
1765
1766
1767
1768 var pathReadlink = newHostFunc(
1769 wasip1.PathReadlinkName, pathReadlinkFn,
1770 []wasm.ValueType{i32, i32, i32, i32, i32, i32},
1771 "fd", "path", "path_len", "buf", "buf_len", "result.bufused",
1772 )
1773
1774 func pathReadlinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1775 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1776
1777 fd := int32(params[0])
1778 path := uint32(params[1])
1779 pathLen := uint32(params[2])
1780 buf := uint32(params[3])
1781 bufLen := uint32(params[4])
1782 resultBufused := uint32(params[5])
1783
1784 if pathLen == 0 || bufLen == 0 {
1785 return experimentalsys.EINVAL
1786 }
1787
1788 mem := mod.Memory()
1789 preopen, p, errno := atPath(fsc, mem, fd, path, pathLen)
1790 if errno != 0 {
1791 return errno
1792 }
1793
1794 dst, errno := preopen.Readlink(p)
1795 if errno != 0 {
1796 return errno
1797 }
1798
1799 if len(dst) > int(bufLen) {
1800 return experimentalsys.ERANGE
1801 }
1802
1803 if ok := mem.WriteString(buf, dst); !ok {
1804 return experimentalsys.EFAULT
1805 }
1806
1807 if !mem.WriteUint32Le(resultBufused, uint32(len(dst))) {
1808 return experimentalsys.EFAULT
1809 }
1810 return 0
1811 }
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835 var pathRemoveDirectory = newHostFunc(
1836 wasip1.PathRemoveDirectoryName, pathRemoveDirectoryFn,
1837 []wasm.ValueType{i32, i32, i32},
1838 "fd", "path", "path_len",
1839 )
1840
1841 func pathRemoveDirectoryFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1842 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1843
1844 fd := int32(params[0])
1845 path := uint32(params[1])
1846 pathLen := uint32(params[2])
1847
1848 preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
1849 if errno != 0 {
1850 return errno
1851 }
1852
1853 return preopen.Rmdir(pathName)
1854 }
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881 var pathRename = newHostFunc(
1882 wasip1.PathRenameName, pathRenameFn,
1883 []wasm.ValueType{i32, i32, i32, i32, i32, i32},
1884 "fd", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
1885 )
1886
1887 func pathRenameFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1888 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1889
1890 fd := int32(params[0])
1891 oldPath := uint32(params[1])
1892 oldPathLen := uint32(params[2])
1893
1894 newFD := int32(params[3])
1895 newPath := uint32(params[4])
1896 newPathLen := uint32(params[5])
1897
1898 oldFS, oldPathName, errno := atPath(fsc, mod.Memory(), fd, oldPath, oldPathLen)
1899 if errno != 0 {
1900 return errno
1901 }
1902
1903 newFS, newPathName, errno := atPath(fsc, mod.Memory(), newFD, newPath, newPathLen)
1904 if errno != 0 {
1905 return errno
1906 }
1907
1908 if oldFS != newFS {
1909 return experimentalsys.ENOSYS
1910 }
1911
1912 return oldFS.Rename(oldPathName, newPathName)
1913 }
1914
1915
1916
1917
1918
1919 var pathSymlink = newHostFunc(
1920 wasip1.PathSymlinkName, pathSymlinkFn,
1921 []wasm.ValueType{i32, i32, i32, i32, i32},
1922 "old_path", "old_path_len", "fd", "new_path", "new_path_len",
1923 )
1924
1925 func pathSymlinkFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
1926 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
1927
1928 oldPath := uint32(params[0])
1929 oldPathLen := uint32(params[1])
1930 fd := int32(params[2])
1931 newPath := uint32(params[3])
1932 newPathLen := uint32(params[4])
1933
1934 mem := mod.Memory()
1935
1936 dir, ok := fsc.LookupFile(fd)
1937 if !ok {
1938 return experimentalsys.EBADF
1939 } else if isDir, errno := dir.File.IsDir(); errno != 0 {
1940 return errno
1941 } else if !isDir {
1942 return experimentalsys.ENOTDIR
1943 }
1944
1945 if oldPathLen == 0 || newPathLen == 0 {
1946 return experimentalsys.EINVAL
1947 }
1948
1949 oldPathBuf, ok := mem.Read(oldPath, oldPathLen)
1950 if !ok {
1951 return experimentalsys.EFAULT
1952 }
1953
1954 newPathBuf, ok := mem.Read(newPath, newPathLen)
1955 if !ok {
1956 return experimentalsys.EFAULT
1957 }
1958
1959 return dir.FS.Symlink(
1960
1961
1962 bufToStr(oldPathBuf),
1963 path.Join(dir.Name, bufToStr(newPathBuf)),
1964 )
1965 }
1966
1967
1968 func bufToStr(buf []byte) string {
1969
1970 return *(*string)(unsafe.Pointer(&buf))
1971 }
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994 var pathUnlinkFile = newHostFunc(
1995 wasip1.PathUnlinkFileName, pathUnlinkFileFn,
1996 []wasm.ValueType{i32, i32, i32},
1997 "fd", "path", "path_len",
1998 )
1999
2000 func pathUnlinkFileFn(_ context.Context, mod api.Module, params []uint64) experimentalsys.Errno {
2001 fsc := mod.(*wasm.ModuleInstance).Sys.FS()
2002
2003 fd := int32(params[0])
2004 path := uint32(params[1])
2005 pathLen := uint32(params[2])
2006
2007 preopen, pathName, errno := atPath(fsc, mod.Memory(), fd, path, pathLen)
2008 if errno != 0 {
2009 return errno
2010 }
2011
2012 return preopen.Unlink(pathName)
2013 }
2014
View as plain text