Skip to content

Commit dcea7bb

Browse files
committed
syscall: libc_wasip2: add fdopendir/readdir/closedir
1 parent 30b5ee7 commit dcea7bb

File tree

1 file changed

+101
-4
lines changed

1 file changed

+101
-4
lines changed

src/syscall/libc_wasip2.go

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -848,23 +848,120 @@ func errorCodeToErrno(err types.ErrorCode) Errno {
848848
return Errno(err)
849849
}
850850

851+
type libc_DIR struct {
852+
d types.DirectoryEntryStream
853+
}
854+
851855
// DIR *fdopendir(int);
852856
//
853857
//go:export fdopendir
854858
func fdopendir(fd int32) unsafe.Pointer {
855-
return nil
859+
if _, ok := wasiStreams[fd]; ok {
860+
libcErrno = EBADF
861+
return nil
862+
}
863+
864+
stream, ok := wasiFiles[fd]
865+
if !ok {
866+
libcErrno = EBADF
867+
return nil
868+
}
869+
if stream.d == cm.ResourceNone {
870+
libcErrno = EBADF
871+
return nil
872+
}
873+
874+
result := stream.d.ReadDirectory()
875+
if err := result.Err(); err != nil {
876+
libcErrno = errorCodeToErrno(*err)
877+
return nil
878+
}
879+
880+
return unsafe.Pointer(&libc_DIR{d: *result.OK()})
856881
}
857882

858883
// int fdclosedir(DIR *);
859884
//
860885
//go:export fdclosedir
861-
func fdclosedir(unsafe.Pointer) int32 {
886+
func fdclosedir(dirp unsafe.Pointer) int32 {
887+
if dirp == nil {
888+
return 0
889+
890+
}
891+
dir := (*libc_DIR)(dirp)
892+
if dir.d == cm.ResourceNone {
893+
return 0
894+
}
895+
896+
dir.d.ResourceDrop()
897+
dir.d = cm.ResourceNone
898+
862899
return 0
863900
}
864901

865902
// struct dirent *readdir(DIR *);
866903
//
867904
//go:export readdir
868-
func readdir(unsafe.Pointer) *Dirent {
869-
return nil
905+
func readdir(dirp unsafe.Pointer) *Dirent {
906+
if dirp == nil {
907+
return nil
908+
909+
}
910+
dir := (*libc_DIR)(dirp)
911+
if dir.d == cm.ResourceNone {
912+
return nil
913+
}
914+
915+
result := dir.d.ReadDirectoryEntry()
916+
if err := result.Err(); err != nil {
917+
libcErrno = errorCodeToErrno(*err)
918+
return nil
919+
}
920+
921+
entry := result.OK().Some()
922+
if entry == nil {
923+
libcErrno = 0
924+
return nil
925+
}
926+
927+
// The dirent C struct uses a flexible array member to indicate that the
928+
// directory name is laid out in memory right after the struct data:
929+
//
930+
// struct dirent {
931+
// ino_t d_ino;
932+
// unsigned char d_type;
933+
// char d_name[];
934+
// };
935+
buf := make([]byte, unsafe.Sizeof(Dirent{})+uintptr(len(entry.Name)))
936+
dirent := (*Dirent)((unsafe.Pointer)(&buf[0]))
937+
938+
// No inodes in wasi
939+
dirent.Ino = 0
940+
dirent.Type = p2fileTypeToLibcType(entry.Type)
941+
copy(buf[unsafe.Offsetof(dirent.Type)+1:], entry.Name)
942+
943+
return dirent
944+
}
945+
946+
func p2fileTypeToLibcType(t types.DescriptorType) uint8 {
947+
switch t {
948+
case types.DescriptorTypeUnknown:
949+
return DT_UNKNOWN
950+
case types.DescriptorTypeBlockDevice:
951+
return DT_BLK
952+
case types.DescriptorTypeCharacterDevice:
953+
return DT_CHR
954+
case types.DescriptorTypeDirectory:
955+
return DT_DIR
956+
case types.DescriptorTypeFIFO:
957+
return DT_FIFO
958+
case types.DescriptorTypeSymbolicLink:
959+
return DT_LNK
960+
case types.DescriptorTypeRegularFile:
961+
return DT_REG
962+
case types.DescriptorTypeSocket:
963+
return DT_FIFO
964+
}
965+
966+
return DT_UNKNOWN
870967
}

0 commit comments

Comments
 (0)