stat_posix.odin 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #+private
  2. #+build darwin, netbsd, freebsd, openbsd
  3. package os2
  4. import "base:runtime"
  5. import "core:sys/posix"
  6. import "core:time"
  7. internal_stat :: proc(stat: posix.stat_t, fullpath: string) -> (fi: File_Info) {
  8. fi.fullpath = fullpath
  9. _, fi.name = split_path(fi.fullpath)
  10. fi.inode = u128(stat.st_ino)
  11. fi.size = i64(stat.st_size)
  12. fi.mode = int(transmute(posix._mode_t)(stat.st_mode - posix.S_IFMT))
  13. fi.type = .Undetermined
  14. switch {
  15. case posix.S_ISBLK(stat.st_mode):
  16. fi.type = .Block_Device
  17. case posix.S_ISCHR(stat.st_mode):
  18. fi.type = .Character_Device
  19. case posix.S_ISDIR(stat.st_mode):
  20. fi.type = .Directory
  21. case posix.S_ISFIFO(stat.st_mode):
  22. fi.type = .Named_Pipe
  23. case posix.S_ISLNK(stat.st_mode):
  24. fi.type = .Symlink
  25. case posix.S_ISREG(stat.st_mode):
  26. fi.type = .Regular
  27. case posix.S_ISSOCK(stat.st_mode):
  28. fi.type = .Socket
  29. }
  30. fi.creation_time = timespec_time(stat.st_birthtimespec)
  31. fi.modification_time = timespec_time(stat.st_mtim)
  32. fi.access_time = timespec_time(stat.st_atim)
  33. timespec_time :: proc(t: posix.timespec) -> time.Time {
  34. return time.Time{_nsec = i64(t.tv_sec) * 1e9 + i64(t.tv_nsec)}
  35. }
  36. return
  37. }
  38. _fstat :: proc(f: ^File, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
  39. if f == nil || f.impl == nil {
  40. err = .Invalid_File
  41. return
  42. }
  43. impl := (^File_Impl)(f.impl)
  44. stat: posix.stat_t
  45. if posix.fstat(impl.fd, &stat) != .OK {
  46. err = _get_platform_error()
  47. return
  48. }
  49. fullpath := clone_string(impl.name, allocator) or_return
  50. return internal_stat(stat, fullpath), nil
  51. }
  52. _stat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
  53. if name == "" {
  54. err = .Invalid_Path
  55. return
  56. }
  57. temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
  58. cname := clone_to_cstring(name, temp_allocator) or_return
  59. fd := posix.open(cname, {})
  60. if fd == -1 {
  61. err = _get_platform_error()
  62. return
  63. }
  64. defer posix.close(fd)
  65. fullpath := _posix_absolute_path(fd, name, allocator) or_return
  66. stat: posix.stat_t
  67. if posix.stat(fullpath, &stat) != .OK {
  68. err = _get_platform_error()
  69. return
  70. }
  71. return internal_stat(stat, string(fullpath)), nil
  72. }
  73. _lstat :: proc(name: string, allocator: runtime.Allocator) -> (fi: File_Info, err: Error) {
  74. if name == "" {
  75. err = .Invalid_Path
  76. return
  77. }
  78. temp_allocator := TEMP_ALLOCATOR_GUARD({ allocator })
  79. // NOTE: can't use realpath or open (+ fcntl F_GETPATH) here because it tries to resolve symlinks.
  80. // NOTE: This might not be correct when given "/symlink/foo.txt",
  81. // you would want that to resolve "/symlink", but not resolve "foo.txt".
  82. fullpath := clean_path(name, temp_allocator) or_return
  83. assert(len(fullpath) > 0)
  84. switch {
  85. case fullpath[0] == '/':
  86. // nothing.
  87. case fullpath == ".":
  88. fullpath = getwd(temp_allocator) or_return
  89. case len(fullpath) > 1 && fullpath[0] == '.' && fullpath[1] == '/':
  90. fullpath = fullpath[2:]
  91. fallthrough
  92. case:
  93. fullpath = concatenate({
  94. getwd(temp_allocator) or_return,
  95. "/",
  96. fullpath,
  97. }, temp_allocator) or_return
  98. }
  99. stat: posix.stat_t
  100. c_fullpath := clone_to_cstring(fullpath, temp_allocator) or_return
  101. if posix.lstat(c_fullpath, &stat) != .OK {
  102. err = _get_platform_error()
  103. return
  104. }
  105. fullpath = clone_string(fullpath, allocator) or_return
  106. return internal_stat(stat, fullpath), nil
  107. }
  108. _same_file :: proc(fi1, fi2: File_Info) -> bool {
  109. return fi1.fullpath == fi2.fullpath
  110. }