stat_linux.odin 4.4 KB

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