file.odin 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. new_file :: proc(handle: uintptr, name: string) -> ^File {
  94. return _new_file(handle, name) or_else panic("Out of memory")
  95. }
  96. @(require_results)
  97. fd :: proc(f: ^File) -> uintptr {
  98. return _fd(f)
  99. }
  100. @(require_results)
  101. name :: proc(f: ^File) -> string {
  102. return _name(f)
  103. }
  104. close :: proc(f: ^File) -> Error {
  105. if f != nil {
  106. return io.close(f.stream)
  107. }
  108. return nil
  109. }
  110. seek :: proc(f: ^File, offset: i64, whence: io.Seek_From) -> (ret: i64, err: Error) {
  111. if f != nil {
  112. return io.seek(f.stream, offset, whence)
  113. }
  114. return 0, .Invalid_File
  115. }
  116. read :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
  117. if f != nil {
  118. return io.read(f.stream, p)
  119. }
  120. return 0, .Invalid_File
  121. }
  122. read_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
  123. if f != nil {
  124. return io.read_at(f.stream, p, offset)
  125. }
  126. return 0, .Invalid_File
  127. }
  128. write :: proc(f: ^File, p: []byte) -> (n: int, err: Error) {
  129. if f != nil {
  130. return io.write(f.stream, p)
  131. }
  132. return 0, .Invalid_File
  133. }
  134. write_at :: proc(f: ^File, p: []byte, offset: i64) -> (n: int, err: Error) {
  135. if f != nil {
  136. return io.write_at(f.stream, p, offset)
  137. }
  138. return 0, .Invalid_File
  139. }
  140. file_size :: proc(f: ^File) -> (n: i64, err: Error) {
  141. if f != nil {
  142. return io.size(f.stream)
  143. }
  144. return 0, .Invalid_File
  145. }
  146. flush :: proc(f: ^File) -> Error {
  147. if f != nil {
  148. return io.flush(f.stream)
  149. }
  150. return nil
  151. }
  152. sync :: proc(f: ^File) -> Error {
  153. return _sync(f)
  154. }
  155. truncate :: proc(f: ^File, size: i64) -> Error {
  156. return _truncate(f, size)
  157. }
  158. remove :: proc(name: string) -> Error {
  159. return _remove(name)
  160. }
  161. rename :: proc(old_path, new_path: string) -> Error {
  162. return _rename(old_path, new_path)
  163. }
  164. link :: proc(old_name, new_name: string) -> Error {
  165. return _link(old_name, new_name)
  166. }
  167. symlink :: proc(old_name, new_name: string) -> Error {
  168. return _symlink(old_name, new_name)
  169. }
  170. read_link :: proc(name: string, allocator: runtime.Allocator) -> (string, Error) {
  171. return _read_link(name,allocator)
  172. }
  173. chdir :: change_directory
  174. change_directory :: proc(name: string) -> Error {
  175. return _chdir(name)
  176. }
  177. chmod :: change_mode
  178. change_mode :: proc(name: string, mode: int) -> Error {
  179. return _chmod(name, mode)
  180. }
  181. chown :: change_owner
  182. change_owner :: proc(name: string, uid, gid: int) -> Error {
  183. return _chown(name, uid, gid)
  184. }
  185. fchdir :: fchange_directory
  186. fchange_directory :: proc(f: ^File) -> Error {
  187. return _fchdir(f)
  188. }
  189. fchmod :: fchange_mode
  190. fchange_mode :: proc(f: ^File, mode: int) -> Error {
  191. return _fchmod(f, mode)
  192. }
  193. fchown :: fchange_owner
  194. fchange_owner :: proc(f: ^File, uid, gid: int) -> Error {
  195. return _fchown(f, uid, gid)
  196. }
  197. lchown :: change_owner_do_not_follow_links
  198. change_owner_do_not_follow_links :: proc(name: string, uid, gid: int) -> Error {
  199. return _lchown(name, uid, gid)
  200. }
  201. chtimes :: change_times
  202. change_times :: proc(name: string, atime, mtime: time.Time) -> Error {
  203. return _chtimes(name, atime, mtime)
  204. }
  205. fchtimes :: fchange_times
  206. fchange_times :: proc(f: ^File, atime, mtime: time.Time) -> Error {
  207. return _fchtimes(f, atime, mtime)
  208. }
  209. @(require_results)
  210. exists :: proc(path: string) -> bool {
  211. return _exists(path)
  212. }
  213. @(require_results)
  214. is_file :: proc(path: string) -> bool {
  215. TEMP_ALLOCATOR_GUARD()
  216. fi, err := stat(path, temp_allocator())
  217. if err != nil {
  218. return false
  219. }
  220. return fi.type == .Regular
  221. }
  222. is_dir :: is_directory
  223. @(require_results)
  224. is_directory :: proc(path: string) -> bool {
  225. TEMP_ALLOCATOR_GUARD()
  226. fi, err := stat(path, temp_allocator())
  227. if err != nil {
  228. return false
  229. }
  230. return fi.type == .Directory
  231. }
  232. copy_file :: proc(dst_path, src_path: string) -> Error {
  233. src := open(src_path) or_return
  234. defer close(src)
  235. info := fstat(src, file_allocator()) or_return
  236. defer file_info_delete(info, file_allocator())
  237. if info.type == .Directory {
  238. return .Invalid_File
  239. }
  240. dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & 0o777) or_return
  241. defer close(dst)
  242. _, err := io.copy(to_writer(dst), to_reader(src))
  243. return err
  244. }