dir_posix.odin 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. //+private
  2. //+build darwin, netbsd, freebsd, openbsd
  3. package os2
  4. import "core:sys/posix"
  5. Read_Directory_Iterator_Impl :: struct {
  6. dir: posix.DIR,
  7. idx: int,
  8. fullpath: [dynamic]byte,
  9. }
  10. @(require_results)
  11. _read_directory_iterator :: proc(it: ^Read_Directory_Iterator) -> (fi: File_Info, index: int, ok: bool) {
  12. fimpl := (^File_Impl)(it.f.impl)
  13. index = it.impl.idx
  14. it.impl.idx += 1
  15. for {
  16. entry := posix.readdir(it.impl.dir)
  17. if entry == nil {
  18. // NOTE(laytan): would be good to have an `error` field on the `Read_Directory_Iterator`
  19. // There isn't a way to now know if it failed or if we are at the end.
  20. return
  21. }
  22. cname := cstring(raw_data(entry.d_name[:]))
  23. if cname == "." || cname == ".." {
  24. continue
  25. }
  26. sname := string(cname)
  27. stat: posix.stat_t
  28. if posix.fstatat(posix.dirfd(it.impl.dir), cname, &stat, { .SYMLINK_NOFOLLOW }) != .OK {
  29. // NOTE(laytan): would be good to have an `error` field on the `Read_Directory_Iterator`
  30. // There isn't a way to now know if it failed or if we are at the end.
  31. return
  32. }
  33. n := len(fimpl.name)+1
  34. non_zero_resize(&it.impl.fullpath, n+len(sname))
  35. n += copy(it.impl.fullpath[n:], sname)
  36. fi = internal_stat(stat, string(it.impl.fullpath[:]))
  37. ok = true
  38. return
  39. }
  40. }
  41. @(require_results)
  42. _read_directory_iterator_create :: proc(f: ^File) -> (iter: Read_Directory_Iterator, err: Error) {
  43. if f == nil || f.impl == nil {
  44. err = .Invalid_File
  45. return
  46. }
  47. impl := (^File_Impl)(f.impl)
  48. iter.f = f
  49. iter.impl.idx = 0
  50. iter.impl.fullpath.allocator = file_allocator()
  51. append(&iter.impl.fullpath, impl.name)
  52. append(&iter.impl.fullpath, "/")
  53. defer if err != nil { delete(iter.impl.fullpath) }
  54. // `fdopendir` consumes the file descriptor so we need to `dup` it.
  55. dupfd := posix.dup(impl.fd)
  56. if dupfd == -1 {
  57. err = _get_platform_error()
  58. return
  59. }
  60. defer if err != nil { posix.close(dupfd) }
  61. iter.impl.dir = posix.fdopendir(dupfd)
  62. if iter.impl.dir == nil {
  63. err = _get_platform_error()
  64. return
  65. }
  66. return
  67. }
  68. _read_directory_iterator_destroy :: proc(it: ^Read_Directory_Iterator) {
  69. if it == nil || it.impl.dir == nil {
  70. return
  71. }
  72. posix.closedir(it.impl.dir)
  73. delete(it.impl.fullpath)
  74. }