fcntl.odin 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  1. package posix
  2. import "core:c"
  3. when ODIN_OS == .Darwin {
  4. foreign import lib "system:System.framework"
  5. } else {
  6. foreign import lib "system:c"
  7. }
  8. // fcntl.h - file control options
  9. foreign lib {
  10. /*
  11. Implemented as `return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode);`
  12. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/creat.html ]]
  13. */
  14. creat :: proc(path: cstring, mode: mode_t) -> FD ---
  15. /*
  16. Perform the operations on open files.
  17. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/fcntl.html ]]
  18. */
  19. fcntl :: proc(fd: FD, cmd: FCNTL_Cmd, #c_vararg args: ..any) -> c.int ---
  20. /*
  21. Establish the connection between a file and a file descriptor.
  22. It shall create an open file description that refers to a file and a file descriptor that
  23. refers to that open file description. The file descriptor is used by other I/O functions to
  24. refer to that file.
  25. The path argument points to a pathname naming the file
  26. Returns: -1 on failure (setting errno), a file descriptor on success.
  27. Example:
  28. // The following example opens the file /tmp/file, either by creating it (if it does not already exist),
  29. // or by truncating its length to 0 (if it does exist). In the former case, if the call creates a new file,
  30. // the access permission bits in the file mode of the file are set to permit reading and writing by the owner,
  31. // and to permit reading only by group members and others.
  32. fd := posix.open("/tmp/file", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
  33. // The following example uses the open() function to try to create the LOCKFILE file and open it for writing.
  34. // Since the open() function specifies the O_EXCL flag, the call fails if the file already exists.
  35. // In that case, the program assumes that someone else is updating the password file and exits.
  36. fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .EXCL }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
  37. if fd == -1 {
  38. fmt.println("cannot open /etc/ptmp")
  39. }
  40. // The following example opens a file for writing, creating the file if it does not already exist.
  41. // If the file does exist, the system truncates the file to zero bytes.
  42. fd := posix.open("/etc/ptmp", { .WRONLY, .CREAT, .TRUNC }, { .IRUSR, .IWUSR, .IRGRP, .IROTH })
  43. if fd == -1 {
  44. fmt.println("cannot open output file")
  45. }
  46. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]]
  47. */
  48. open :: proc(path: cstring, flags: O_Flags, #c_vararg mode: ..mode_t) -> FD ---
  49. /*
  50. Equivalent to the open() function except in the case where path specifies a relative path.
  51. In this case the file to be opened is determined relative to the directory associated with the
  52. file descriptor fd instead of the current working directory.
  53. Returns: -1 on failure (setting errno), a file descriptor on success.
  54. [[ More; https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html ]]
  55. */
  56. openat :: proc(fd: FD, path: cstring, flags: O_Flags, mode: mode_t = {}) -> FD ---
  57. }
  58. FCNTL_Cmd :: enum c.int {
  59. DUPFD = F_DUPFD,
  60. DUPFD_CLOEXEC = F_DUPFD_CLOEXEC,
  61. GETFD = F_GETFD,
  62. SETFD = F_SETFD,
  63. GETFL = F_GETFL,
  64. SETFL = F_SETFL,
  65. GETLK = F_GETLK,
  66. SETLK = F_SETLK,
  67. SETLKW = F_SETLKW,
  68. GETOWN = F_GETOWN,
  69. SETOWN = F_SETOWN,
  70. }
  71. Lock_Type :: enum c.short {
  72. RDLCK = F_RDLCK,
  73. UNLCK = F_UNLCK,
  74. WRLCK = F_WRLCK,
  75. }
  76. // Assertions made to unify this bit set.
  77. #assert(O_RDONLY == 0)
  78. O_Flag_Bits :: enum c.int {
  79. // Sets FD_CLOEXEC on the file descriptor.
  80. CLOEXEC = log2(O_CLOEXEC),
  81. // If not exists, combined with DIRECTORY will cause creation of a directory, otherwise a regular file.
  82. CREAT = log2(O_CREAT),
  83. // Fails if the opened descriptor would not be a directory.
  84. DIRECTORY = log2(O_DIRECTORY),
  85. // If combined with CREAT, causes a failure if the file already exists.
  86. EXCL = log2(O_EXCL),
  87. // If terminal device, do not make it the controlling terminal for the process.
  88. NOCTTY = log2(O_NOCTTY),
  89. // Don't follow symbolic links, fail with errno ELOOP.
  90. NOFOLLOW = log2(O_NOFOLOW),
  91. // If exists and regular, truncate the length to 0.
  92. TRUNC = log2(O_TRUNC),
  93. // NOTE: use with `posix.O_TTY_INIT + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
  94. // this bit set enum because it is 0 on some platforms and a value on others.
  95. // TTY_INIT = O_TTY_INIT,
  96. // Set file offset to end of file prior to each write.
  97. APPEND = log2(O_APPEND),
  98. // Write I/O shall complete as defined by synchronized I/O data integrity completion.
  99. DSYNC = log2(O_DSYNC),
  100. // Causes nonblocking behaviour in various situations.
  101. NONBLOCK = log2(O_NONBLOCK),
  102. // Write I/O shall complete as defined by synchronized I/O file integrity completion.
  103. SYNC = log2(O_SYNC),
  104. // NOTE: use with `posix.O_RSYNC + { .OTHER_FLAG, .OTHER_FLAG }`, unfortunately can't be in
  105. // this bit set enum because it is 0 on some platforms and a value on others.
  106. // RSYNC = O_RSYNC,
  107. // Execute only.
  108. EXEC = log2(O_EXEC),
  109. // Reading and writing.
  110. RDWR = log2(O_RDWR),
  111. // Writing only.
  112. WRONLY = log2(O_WRONLY),
  113. // Reading only.
  114. // RDONLY = 0, // Default
  115. }
  116. O_Flags :: bit_set[O_Flag_Bits; c.int]
  117. // A mask of all the access mode bits.
  118. O_ACCMODE :: O_Flags{ .EXEC, .RDWR, .WRONLY }
  119. AT_Flag_Bits :: enum c.int {
  120. EACCESS = log2(AT_EACCESS),
  121. SYMLINK_NOFOLLOW = log2(AT_SYMLINK_NOFOLLOW),
  122. SYMLINK_FOLLOW = log2(AT_SYMLINK_FOLLOW),
  123. REMOVEDIR = log2(AT_REMOVEDIR),
  124. }
  125. AT_Flags :: bit_set[AT_Flag_Bits; c.int]
  126. when ODIN_OS == .Darwin {
  127. off_t :: distinct c.int64_t
  128. pid_t :: distinct c.int32_t
  129. F_DUPFD :: 0
  130. F_DUPFD_CLOEXEC :: 67
  131. F_GETFD :: 1
  132. F_SETFD :: 2
  133. F_GETFL :: 3
  134. F_SETFL :: 4
  135. F_GETLK :: 7
  136. F_SETLK :: 8
  137. F_SETLKW :: 9
  138. F_GETOWN :: 5
  139. F_SETOWN :: 6
  140. FD_CLOEXEC :: 1
  141. F_RDLCK :: 1
  142. F_UNLCK :: 2
  143. F_WRLCK :: 3
  144. O_CLOEXEC :: 0x01000000
  145. O_CREAT :: 0x00000200
  146. O_DIRECTORY :: 0x00100000
  147. O_EXCL :: 0x00000800
  148. O_NOCTTY :: 0x00020000
  149. O_NOFOLOW :: 0x00000100
  150. O_TRUNC :: 0x00000400
  151. _O_TTY_INIT :: 0
  152. O_TTY_INIT :: O_Flags{}
  153. O_APPEND :: 0x00000008
  154. O_DSYNC :: 0x00400000
  155. O_NONBLOCK :: 0x00000004
  156. O_SYNC :: 0x0080
  157. _O_RSYNC :: 0
  158. O_RSYNC :: O_Flags{}
  159. O_EXEC :: 0x40000000
  160. O_RDONLY :: 0
  161. O_RDWR :: 0x0002
  162. O_WRONLY :: 0x0001
  163. _O_SEARCH :: O_EXEC | O_DIRECTORY
  164. O_SEARCH :: O_Flags{ .EXEC, .DIRECTORY }
  165. AT_FDCWD: FD: -2
  166. AT_EACCESS :: 0x0010
  167. AT_SYMLINK_NOFOLLOW :: 0x0020
  168. AT_SYMLINK_FOLLOW :: 0x0040
  169. AT_REMOVEDIR :: 0x0080
  170. flock :: struct {
  171. l_start: off_t, /* [PSX] relative offset in bytes */
  172. l_len: off_t, /* [PSX] size; if 0 then until EOF */
  173. l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
  174. l_type: Lock_Type, /* [PSX] type of lock */
  175. l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
  176. }
  177. } else when ODIN_OS == .FreeBSD {
  178. off_t :: distinct c.int64_t
  179. pid_t :: distinct c.int32_t
  180. F_DUPFD :: 0
  181. F_DUPFD_CLOEXEC :: 17
  182. F_GETFD :: 1
  183. F_SETFD :: 2
  184. F_GETFL :: 3
  185. F_SETFL :: 4
  186. F_GETLK :: 7
  187. F_SETLK :: 8
  188. F_SETLKW :: 9
  189. F_GETOWN :: 5
  190. F_SETOWN :: 6
  191. FD_CLOEXEC :: 1
  192. F_RDLCK :: 1
  193. F_UNLCK :: 2
  194. F_WRLCK :: 3
  195. O_CLOEXEC :: 0x00100000
  196. O_CREAT :: 0x0200
  197. O_DIRECTORY :: 0x00020000
  198. O_EXCL :: 0x0800
  199. O_NOCTTY :: 0x8000
  200. O_NOFOLOW :: 0x0100
  201. O_TRUNC :: 0x0400
  202. _O_TTY_INIT :: 0x00080000
  203. O_TTY_INIT :: O_Flags{O_Flag_Bits(log2(_O_TTY_INIT))}
  204. O_APPEND :: 0x0008
  205. O_DSYNC :: 0x01000000
  206. O_NONBLOCK :: 0x0004
  207. O_SYNC :: 0x0080
  208. _O_RSYNC :: 0
  209. O_RSYNC :: O_Flags{} // NOTE: not defined in headers
  210. O_EXEC :: 0x00040000
  211. O_RDONLY :: 0
  212. O_RDWR :: 0x0002
  213. O_WRONLY :: 0x0001
  214. _O_SEARCH :: O_EXEC
  215. O_SEARCH :: O_Flags{ .EXEC }
  216. AT_FDCWD: FD: -100
  217. AT_EACCESS :: 0x0100
  218. AT_SYMLINK_NOFOLLOW :: 0x0200
  219. AT_SYMLINK_FOLLOW :: 0x0400
  220. AT_REMOVEDIR :: 0x0800
  221. flock :: struct {
  222. l_start: off_t, /* [PSX] relative offset in bytes */
  223. l_len: off_t, /* [PSX] size; if 0 then until EOF */
  224. l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
  225. l_type: Lock_Type, /* [PSX] type of lock */
  226. l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
  227. l_sysid: c.int,
  228. }
  229. } else when ODIN_OS == .NetBSD {
  230. off_t :: distinct c.int64_t
  231. pid_t :: distinct c.int32_t
  232. F_DUPFD :: 0
  233. F_DUPFD_CLOEXEC :: 12
  234. F_GETFD :: 1
  235. F_SETFD :: 2
  236. F_GETFL :: 3
  237. F_SETFL :: 4
  238. F_GETLK :: 7
  239. F_SETLK :: 8
  240. F_SETLKW :: 9
  241. F_GETOWN :: 5
  242. F_SETOWN :: 6
  243. FD_CLOEXEC :: 1
  244. F_RDLCK :: 1
  245. F_UNLCK :: 2
  246. F_WRLCK :: 3
  247. O_CLOEXEC :: 0x00400000
  248. O_CREAT :: 0x0200
  249. O_DIRECTORY :: 0x0020000
  250. O_EXCL :: 0x0800
  251. O_NOCTTY :: 0x8000
  252. O_NOFOLOW :: 0x0100
  253. O_TRUNC :: 0x0400
  254. _O_TTY_INIT :: 0
  255. O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers
  256. O_APPEND :: 0x0008
  257. O_DSYNC :: 0x010000
  258. O_NONBLOCK :: 0x0004
  259. O_SYNC :: 0x0080
  260. _O_RSYNC :: 0x0002
  261. O_RSYNC :: O_Flags{O_Flag_Bits(log2(_O_RSYNC))}
  262. O_EXEC :: 0x04000000
  263. O_RDONLY :: 0
  264. O_RDWR :: 0x0002
  265. O_WRONLY :: 0x0001
  266. _O_SEARCH :: 0x00800000
  267. O_SEARCH :: O_Flags{O_Flag_Bits(log2(_O_SEARCH))}
  268. AT_FDCWD: FD: -100
  269. AT_EACCESS :: 0x100
  270. AT_SYMLINK_NOFOLLOW :: 0x200
  271. AT_SYMLINK_FOLLOW :: 0x400
  272. AT_REMOVEDIR :: 0x800
  273. flock :: struct {
  274. l_start: off_t, /* [PSX] relative offset in bytes */
  275. l_len: off_t, /* [PSX] size; if 0 then until EOF */
  276. l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
  277. l_type: Lock_Type, /* [PSX] type of lock */
  278. l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
  279. }
  280. } else when ODIN_OS == .OpenBSD {
  281. off_t :: distinct c.int64_t
  282. pid_t :: distinct c.int32_t
  283. F_DUPFD :: 0
  284. F_DUPFD_CLOEXEC :: 10
  285. F_GETFD :: 1
  286. F_SETFD :: 2
  287. F_GETFL :: 3
  288. F_SETFL :: 4
  289. F_GETLK :: 7
  290. F_SETLK :: 8
  291. F_SETLKW :: 9
  292. F_GETOWN :: 5
  293. F_SETOWN :: 6
  294. FD_CLOEXEC :: 1
  295. F_RDLCK :: 1
  296. F_UNLCK :: 2
  297. F_WRLCK :: 3
  298. O_CLOEXEC :: 0x10000
  299. O_CREAT :: 0x0200
  300. O_DIRECTORY :: 0x20000
  301. O_EXCL :: 0x0800
  302. O_NOCTTY :: 0x8000
  303. O_NOFOLOW :: 0x0100
  304. O_TRUNC :: 0x0400
  305. _O_TTY_INIT :: 0
  306. O_TTY_INIT :: O_Flags{} // NOTE: not defined in the headers
  307. O_APPEND :: 0x0008
  308. O_DSYNC :: 0x010000
  309. O_NONBLOCK :: 0x0004
  310. O_SYNC :: 0x0080
  311. _O_RSYNC :: O_SYNC
  312. O_RSYNC :: O_Flags{ .SYNC }
  313. O_EXEC :: 0x04000000 // NOTE: not defined in the headers
  314. O_RDONLY :: 0
  315. O_RDWR :: 0x0002
  316. O_WRONLY :: 0x0001
  317. _O_SEARCH :: 0
  318. O_SEARCH :: O_Flags{} // NOTE: not defined in the headers
  319. AT_FDCWD: FD: -100
  320. AT_EACCESS :: 0x01
  321. AT_SYMLINK_NOFOLLOW :: 0x02
  322. AT_SYMLINK_FOLLOW :: 0x04
  323. AT_REMOVEDIR :: 0x08
  324. flock :: struct {
  325. l_start: off_t, /* [PSX] relative offset in bytes */
  326. l_len: off_t, /* [PSX] size; if 0 then until EOF */
  327. l_pid: pid_t, /* [PSX] process ID of the process holding the lock */
  328. l_type: Lock_Type, /* [PSX] type of lock */
  329. l_whence: c.short, /* [PSX] flag (Whence) of starting offset */
  330. }
  331. } else {
  332. #panic("posix is unimplemented for the current target")
  333. }