stat_linux.odin 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. //+private
  2. package os2
  3. import "core:time"
  4. import "core:runtime"
  5. import "core:sys/unix"
  6. import "core:path/filepath"
  7. // File type
  8. S_IFMT :: 0o170000 // Type of file mask
  9. S_IFIFO :: 0o010000 // Named pipe (fifo)
  10. S_IFCHR :: 0o020000 // Character special
  11. S_IFDIR :: 0o040000 // Directory
  12. S_IFBLK :: 0o060000 // Block special
  13. S_IFREG :: 0o100000 // Regular
  14. S_IFLNK :: 0o120000 // Symbolic link
  15. S_IFSOCK :: 0o140000 // Socket
  16. // File mode
  17. // Read, write, execute/search by owner
  18. S_IRWXU :: 0o0700 // RWX mask for owner
  19. S_IRUSR :: 0o0400 // R for owner
  20. S_IWUSR :: 0o0200 // W for owner
  21. S_IXUSR :: 0o0100 // X for owner
  22. // Read, write, execute/search by group
  23. S_IRWXG :: 0o0070 // RWX mask for group
  24. S_IRGRP :: 0o0040 // R for group
  25. S_IWGRP :: 0o0020 // W for group
  26. S_IXGRP :: 0o0010 // X for group
  27. // Read, write, execute/search by others
  28. S_IRWXO :: 0o0007 // RWX mask for other
  29. S_IROTH :: 0o0004 // R for other
  30. S_IWOTH :: 0o0002 // W for other
  31. S_IXOTH :: 0o0001 // X for other
  32. S_ISUID :: 0o4000 // Set user id on execution
  33. S_ISGID :: 0o2000 // Set group id on execution
  34. S_ISVTX :: 0o1000 // Directory restrcted delete
  35. S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
  36. S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
  37. S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
  38. S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
  39. S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
  40. S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
  41. S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
  42. F_OK :: 0 // Test for file existance
  43. X_OK :: 1 // Test for execute permission
  44. W_OK :: 2 // Test for write permission
  45. R_OK :: 4 // Test for read permission
  46. @private
  47. Unix_File_Time :: struct {
  48. seconds: i64,
  49. nanoseconds: i64,
  50. }
  51. @private
  52. _Stat :: struct {
  53. device_id: u64, // ID of device containing file
  54. serial: u64, // File serial number
  55. nlink: u64, // Number of hard links
  56. mode: u32, // Mode of the file
  57. uid: u32, // User ID of the file's owner
  58. gid: u32, // Group ID of the file's group
  59. _padding: i32, // 32 bits of padding
  60. rdev: u64, // Device ID, if device
  61. size: i64, // Size of the file, in bytes
  62. block_size: i64, // Optimal bllocksize for I/O
  63. blocks: i64, // Number of 512-byte blocks allocated
  64. last_access: Unix_File_Time, // Time of last access
  65. modified: Unix_File_Time, // Time of last modification
  66. status_change: Unix_File_Time, // Time of last status change
  67. _reserve1,
  68. _reserve2,
  69. _reserve3: i64,
  70. }
  71. _fstat :: proc(f: ^File, allocator := context.allocator) -> (File_Info, Error) {
  72. return _fstat_internal(f.impl.fd, allocator)
  73. }
  74. _fstat_internal :: proc(fd: int, allocator: runtime.Allocator) -> (File_Info, Error) {
  75. s: _Stat
  76. result := unix.sys_fstat(fd, &s)
  77. if result < 0 {
  78. return {}, _get_platform_error(result)
  79. }
  80. // TODO: As of Linux 4.11, the new statx syscall can retrieve creation_time
  81. fi := File_Info {
  82. fullpath = _get_full_path(fd, allocator),
  83. name = "",
  84. size = s.size,
  85. mode = 0,
  86. is_dir = S_ISDIR(s.mode),
  87. modification_time = time.Time {s.modified.seconds},
  88. access_time = time.Time {s.last_access.seconds},
  89. creation_time = time.Time{0}, // regular stat does not provide this
  90. }
  91. fi.name = filepath.base(fi.fullpath)
  92. return fi, nil
  93. }
  94. // NOTE: _stat and _lstat are using _fstat to avoid a race condition when populating fullpath
  95. _stat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
  96. name_cstr, allocated := _name_to_cstring(name)
  97. defer if allocated {
  98. delete(name_cstr)
  99. }
  100. fd := unix.sys_open(name_cstr, _O_RDONLY)
  101. if fd < 0 {
  102. return {}, _get_platform_error(fd)
  103. }
  104. defer unix.sys_close(fd)
  105. return _fstat_internal(fd, allocator)
  106. }
  107. _lstat :: proc(name: string, allocator := context.allocator) -> (File_Info, Error) {
  108. name_cstr, allocated := _name_to_cstring(name)
  109. defer if allocated {
  110. delete(name_cstr)
  111. }
  112. fd := unix.sys_open(name_cstr, _O_RDONLY | _O_PATH | _O_NOFOLLOW)
  113. if fd < 0 {
  114. return {}, _get_platform_error(fd)
  115. }
  116. defer unix.sys_close(fd)
  117. return _fstat_internal(fd, allocator)
  118. }
  119. _same_file :: proc(fi1, fi2: File_Info) -> bool {
  120. return fi1.fullpath == fi2.fullpath
  121. }
  122. _stat_internal :: proc(name: string) -> (s: _Stat, res: int) {
  123. name_cstr, allocated := _name_to_cstring(name)
  124. defer if allocated {
  125. delete(name_cstr)
  126. }
  127. res = unix.sys_stat(name_cstr, &s)
  128. return
  129. }