dir_wasi.odin 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. #+private
  2. package os2
  3. import "base:runtime"
  4. import "core:slice"
  5. import "base:intrinsics"
  6. import "core:sys/wasm/wasi"
  7. Read_Directory_Iterator_Impl :: struct {
  8. fullpath: [dynamic]byte,
  9. buf: []byte,
  10. off: int,
  11. }
  12. @(require_results)
  13. _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
  14. fimpl := (^File_Impl)(it.f.impl)
  15. buf := it.impl.buf[it.impl.off:]
  16. index = it.index
  17. it.index += 1
  18. for {
  19. if len(buf) < size_of(wasi.dirent_t) {
  20. return
  21. }
  22. entry := intrinsics.unaligned_load((^wasi.dirent_t)(raw_data(buf)))
  23. buf = buf[size_of(wasi.dirent_t):]
  24. assert(len(buf) < int(entry.d_namlen))
  25. name := string(buf[:entry.d_namlen])
  26. buf = buf[entry.d_namlen:]
  27. it.impl.off += size_of(wasi.dirent_t) + int(entry.d_namlen)
  28. if name == "." || name == ".." {
  29. continue
  30. }
  31. n := len(fimpl.name)+1
  32. if alloc_err := non_zero_resize(&it.impl.fullpath, n+len(name)); alloc_err != nil {
  33. read_directory_iterator_set_error(it, name, alloc_err)
  34. ok = true
  35. return
  36. }
  37. copy(it.impl.fullpath[n:], name)
  38. stat, err := wasi.path_filestat_get(__fd(it.f), {}, name)
  39. if err != nil {
  40. // Can't stat, fill what we have from dirent.
  41. stat = {
  42. ino = entry.d_ino,
  43. filetype = entry.d_type,
  44. }
  45. read_directory_iterator_set_error(it, string(it.impl.fullpath[:]), _get_platform_error(err))
  46. }
  47. fi = internal_stat(stat, string(it.impl.fullpath[:]))
  48. ok = true
  49. return
  50. }
  51. }
  52. _read_directory_iterator_init :: proc(it: ^Read_Directory_Iterator, f: ^File) {
  53. // NOTE: Allow calling `init` to target a new directory with the same iterator.
  54. it.impl.off = 0
  55. if f == nil || f.impl == nil {
  56. read_directory_iterator_set_error(it, "", .Invalid_File)
  57. return
  58. }
  59. impl := (^File_Impl)(f.impl)
  60. buf: [dynamic]byte
  61. // NOTE: Allow calling `init` to target a new directory with the same iterator.
  62. if it.impl.buf != nil {
  63. buf = slice.into_dynamic(it.impl.buf)
  64. }
  65. buf.allocator = file_allocator()
  66. defer if it.err.err != nil { delete(buf) }
  67. for {
  68. if err := non_zero_resize(&buf, 512 if len(buf) == 0 else len(buf)*2); err != nil {
  69. read_directory_iterator_set_error(it, name(f), err)
  70. return
  71. }
  72. n, err := wasi.fd_readdir(__fd(f), buf[:], 0)
  73. if err != nil {
  74. read_directory_iterator_set_error(it, name(f), _get_platform_error(err))
  75. return
  76. }
  77. if n < len(buf) {
  78. non_zero_resize(&buf, n)
  79. break
  80. }
  81. assert(n == len(buf))
  82. }
  83. it.impl.buf = buf[:]
  84. // NOTE: Allow calling `init` to target a new directory with the same iterator.
  85. it.impl.fullpath.allocator = file_allocator()
  86. clear(&it.impl.fullpath)
  87. if err := reserve(&it.impl.fullpath, len(impl.name)+128); err != nil {
  88. read_directory_iterator_set_error(it, name(f), err)
  89. return
  90. }
  91. append(&it.impl.fullpath, impl.name)
  92. append(&it.impl.fullpath, "/")
  93. return
  94. }
  95. _read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
  96. delete(it.impl.buf, file_allocator())
  97. delete(it.impl.fullpath)
  98. }