file.odin 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. package os2
  2. import "core:io"
  3. import "core:time"
  4. import "base:runtime"
  5. /*
  6. Type representing a file handle.
  7. This struct represents an OS-specific file-handle, which can be one of
  8. the following:
  9. - File
  10. - Directory
  11. - Pipe
  12. - Named pipe
  13. - Block Device
  14. - Character device
  15. - Symlink
  16. - Socket
  17. See `File_Type` enum for more information on file types.
  18. */
  19. File :: struct {
  20. impl: rawptr,
  21. stream: io.Stream,
  22. fstat: Fstat_Callback,
  23. }
  24. /*
  25. Type representing the type of a file handle.
  26. **Note(windows)**: Socket handles can not be distinguished from
  27. files, as they are just a normal file handle that is being treated by
  28. a special driver. Windows also makes no distinction between block and
  29. character devices.
  30. */
  31. File_Type :: enum {
  32. // The type of a file could not be determined for the current platform.
  33. Undetermined,
  34. // Represents a regular file.
  35. Regular,
  36. // Represents a directory.
  37. Directory,
  38. // Represents a symbolic link.
  39. Symlink,
  40. // Represents a named pipe (FIFO).
  41. Named_Pipe,
  42. // Represents a socket.
  43. // **Note(windows)**: Not returned on windows
  44. Socket,
  45. // Represents a block device.
  46. // **Note(windows)**: On windows represents all devices.
  47. Block_Device,
  48. // Represents a character device.
  49. // **Note(windows)**: Not returned on windows
  50. Character_Device,
  51. }
  52. File_Flags :: distinct bit_set[File_Flag; uint]
  53. File_Flag :: enum {
  54. Read,
  55. Write,
  56. Append,
  57. Create,
  58. Excl,
  59. Sync,
  60. Trunc,
  61. Sparse,
  62. Inheritable,
  63. Unbuffered_IO,
  64. }
  65. O_RDONLY :: File_Flags{.Read}
  66. O_WRONLY :: File_Flags{.Write}
  67. O_RDWR :: File_Flags{.Read, .Write}
  68. O_APPEND :: File_Flags{.Append}
  69. O_CREATE :: File_Flags{.Create}
  70. O_EXCL :: File_Flags{.Excl}
  71. O_SYNC :: File_Flags{.Sync}
  72. O_TRUNC :: File_Flags{.Trunc}
  73. O_SPARSE :: File_Flags{.Sparse}
  74. /*
  75. If specified, the file handle is inherited upon the creation of a child
  76. process. By default all handles are created non-inheritable.
  77. **Note**: The standard file handles (stderr, stdout and stdin) are always
  78. initialized as inheritable.
  79. */
  80. O_INHERITABLE :: File_Flags{.Inheritable}
  81. stdin: ^File = nil // OS-Specific
  82. stdout: ^File = nil // OS-Specific
  83. stderr: ^File = nil // OS-Specific
  84. @(require_results)
  85. create :: proc(name: string) -> (^File, Error) {
  86. return open(name, {.Read, .Write, .Create}, 0o777)
  87. }
  88. @(require_results)
  89. open :: proc(name: string, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) {
  90. return _open(name, flags, perm)
  91. }
  92. // @(require_results)
  93. // open_buffered :: proc(name: string, buffer_size: uint, flags := File_Flags{.Read}, perm := 0o777) -> (^File, Error) {
  94. // if buffer_size == 0 {
  95. // return _open(name, flags, perm)
  96. // }
  97. // return _open_buffered(name, buffer_size, flags, perm)
  98. // }
  99. @(require_results)
  100. new_file :: proc(handle: uintptr, name: string) -> ^File {
  101. file, err := _new_file(handle, name)
  102. if err != nil {
  103. panic(error_string(err))
  104. }
  105. return file
  106. }
  107. @(require_results)
  108. fd :: proc(f: ^File) -> uintptr {
  109. return _fd(f)
  110. }
  111. @(require_results)
  112. name :: proc(f: ^File) -> string {
  113. return _name(f)
  114. }
  115. /*
  116. Close a file and its stream.
  117. Any further use of the file or its stream should be considered to be in the
  118. same class of bugs as a use-after-free.
  119. */
  120. close :: proc(f: ^File) -> Error {
  121. if f != nil {
  122. return io.close(f.stream)
  123. }
  124. return nil
  125. }
  126. seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
  127. if f != nil {
  128. return io.seek(f.stream, offset, whence)
  129. }
  130. return 0, .Invalid_File
  131. }
  132. read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
  133. if f != nil {
  134. return io.read(f.stream, p)
  135. }
  136. return 0, .Invalid_File
  137. }
  138. read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
  139. if f != nil {
  140. return io.read_at(f.stream, p, offset)
  141. }
  142. return 0, .Invalid_File
  143. }
  144. write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
  145. if f != nil {
  146. return io.write(f.stream, p)
  147. }
  148. return 0, .Invalid_File
  149. }
  150. write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
  151. if f != nil {
  152. return io.write_at(f.stream, p, offset)
  153. }
  154. return 0, .Invalid_File
  155. }
  156. file_size :: proc(f: ^File) -> (n: i64, err: Error) {
  157. if f != nil {
  158. return io.size(f.stream)
  159. }
  160. return 0, .Invalid_File
  161. }
  162. flush :: proc(f: ^File) -> Error {
  163. if f != nil {
  164. return io.flush(f.stream)
  165. }
  166. return nil
  167. }
  168. sync :: proc(f: ^File) -> Error {
  169. return _sync(f)
  170. }
  171. truncate :: proc(f: ^File, size: i64) -> Error {
  172. return _truncate(f, size)
  173. }
  174. remove :: proc(name: string) -> Error {
  175. return _remove(name)
  176. }
  177. rename :: proc(old_path, new_path: string) -> Error {
  178. return _rename(old_path, new_path)
  179. }
  180. link :: proc(old_name, new_name: string) -> Error {
  181. return _link(old_name, new_name)
  182. }
  183. symlink :: proc(old_name, new_name: string) -> Error {
  184. return _symlink(old_name, new_name)
  185. }
  186. read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
  187. return _read_link(name,allocator)
  188. }
  189. chdir :: change_directory
  190. change_directory :: proc(name: string) -> Error {
  191. return _chdir(name)
  192. }
  193. chmod :: change_mode
  194. change_mode :: proc(name: string, mode: int) -> Error {
  195. return _chmod(name, mode)
  196. }
  197. chown :: change_owner
  198. change_owner :: proc(name: string, uid, gid: int) -> Error {
  199. return _chown(name, uid, gid)
  200. }
  201. fchdir :: fchange_directory
  202. fchange_directory :: proc(f: ^File) -> Error {
  203. return _fchdir(f)
  204. }
  205. fchmod :: fchange_mode
  206. fchange_mode :: proc(f: ^File, mode: int) -> Error {
  207. return _fchmod(f, mode)
  208. }
  209. fchown :: fchange_owner
  210. fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
  211. return _fchown(f, uid, gid)
  212. }
  213. lchown :: change_owner_do_not_follow_links
  214. change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
  215. return _lchown(name, uid, gid)
  216. }
  217. chtimes :: change_times
  218. change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
  219. return _chtimes(name, atime, mtime)
  220. }
  221. fchtimes :: fchange_times
  222. fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
  223. return _fchtimes(f, atime, mtime)
  224. }
  225. @(require_results)
  226. exists :: proc(path: string) -> bool {
  227. return _exists(path)
  228. }
  229. @(require_results)
  230. is_file :: proc(path: string) -> bool {
  231. TEMP_ALLOCATOR_GUARD()
  232. fi, err := stat(path, temp_allocator())
  233. if err != nil {
  234. return false
  235. }
  236. return fi.type == .Regular
  237. }
  238. is_dir :: is_directory
  239. @(require_results)
  240. is_directory :: proc(path: string) -> bool {
  241. TEMP_ALLOCATOR_GUARD()
  242. fi, err := stat(path, temp_allocator())
  243. if err != nil {
  244. return false
  245. }
  246. return fi.type == .Directory
  247. }
  248. copy_file :: proc(dst_path, src_path: string) -> Error {
  249. src := open(src_path) or_return
  250. defer close(src)
  251. info := fstat(src, file_allocator()) or_return
  252. defer file_info_delete(info, file_allocator())
  253. if info.type == .Directory {
  254. return .Invalid_File
  255. }
  256. dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & 0o777) or_return
  257. defer close(dst)
  258. _, err := io.copy(to_writer(dst), to_reader(src))
  259. return err
  260. }