os_windows.odin 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #import w "sys/windows.odin";
  2. #import "fmt.odin";
  3. Handle :: int;
  4. File_Time :: u64;
  5. Errno :: int;
  6. INVALID_HANDLE: Handle : -1;
  7. O_RDONLY :: 0x00000;
  8. O_WRONLY :: 0x00001;
  9. O_RDWR :: 0x00002;
  10. O_CREAT :: 0x00040;
  11. O_EXCL :: 0x00080;
  12. O_NOCTTY :: 0x00100;
  13. O_TRUNC :: 0x00200;
  14. O_NONBLOCK :: 0x00800;
  15. O_APPEND :: 0x00400;
  16. O_SYNC :: 0x01000;
  17. O_ASYNC :: 0x02000;
  18. O_CLOEXEC :: 0x80000;
  19. ERROR_NONE: Errno : 0;
  20. ERROR_FILE_NOT_FOUND: Errno : 2;
  21. ERROR_PATH_NOT_FOUND: Errno : 3;
  22. ERROR_ACCESS_DENIED: Errno : 5;
  23. ERROR_NO_MORE_FILES: Errno : 18;
  24. ERROR_HANDLE_EOF: Errno : 38;
  25. ERROR_NETNAME_DELETED: Errno : 64;
  26. ERROR_FILE_EXISTS: Errno : 80;
  27. ERROR_BROKEN_PIPE: Errno : 109;
  28. ERROR_BUFFER_OVERFLOW: Errno : 111;
  29. ERROR_INSUFFICIENT_BUFFER: Errno : 122;
  30. ERROR_MOD_NOT_FOUND: Errno : 126;
  31. ERROR_PROC_NOT_FOUND: Errno : 127;
  32. ERROR_DIR_NOT_EMPTY: Errno : 145;
  33. ERROR_ALREADY_EXISTS: Errno : 183;
  34. ERROR_ENVVAR_NOT_FOUND: Errno : 203;
  35. ERROR_MORE_DATA: Errno : 234;
  36. ERROR_OPERATION_ABORTED: Errno : 995;
  37. ERROR_IO_PENDING: Errno : 997;
  38. ERROR_NOT_FOUND: Errno : 1168;
  39. ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
  40. WSAEACCES: Errno : 10013;
  41. WSAECONNRESET: Errno : 10054;
  42. // Windows reserves errors >= 1<<29 for application use
  43. ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
  44. open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
  45. if path.count == 0 {
  46. return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
  47. }
  48. access: u32;
  49. match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
  50. case O_RDONLY: access = w.FILE_GENERIC_READ;
  51. case O_WRONLY: access = w.FILE_GENERIC_WRITE;
  52. case O_RDWR: access = w.FILE_GENERIC_READ | w.FILE_GENERIC_WRITE;
  53. }
  54. if mode&O_CREAT != 0 {
  55. access |= w.FILE_GENERIC_WRITE;
  56. }
  57. if mode&O_APPEND != 0 {
  58. access &~= w.FILE_GENERIC_WRITE;
  59. access |= w.FILE_APPEND_DATA;
  60. }
  61. share_mode := cast(u32)(w.FILE_SHARE_READ|w.FILE_SHARE_WRITE);
  62. sa: ^w.Security_Attributes = nil;
  63. sa_inherit := w.Security_Attributes{length = size_of(w.Security_Attributes), inherit_handle = 1};
  64. if mode&O_CLOEXEC == 0 {
  65. sa = ^sa_inherit;
  66. }
  67. create_mode: u32;
  68. match {
  69. case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
  70. create_mode = w.CREATE_NEW;
  71. case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
  72. create_mode = w.CREATE_ALWAYS;
  73. case mode&O_CREAT == O_CREAT:
  74. create_mode = w.OPEN_ALWAYS;
  75. case mode&O_TRUNC == O_TRUNC:
  76. create_mode = w.TRUNCATE_EXISTING;
  77. default:
  78. create_mode = w.OPEN_EXISTING;
  79. }
  80. buf: [300]byte;
  81. copy(buf[..], cast([]byte)path);
  82. handle := cast(Handle)w.CreateFileA(^buf[0], access, share_mode, sa, create_mode, w.FILE_ATTRIBUTE_NORMAL, nil);
  83. if handle != INVALID_HANDLE {
  84. return handle, ERROR_NONE;
  85. }
  86. err := w.GetLastError();
  87. return INVALID_HANDLE, cast(Errno)err;
  88. }
  89. close :: proc(fd: Handle) {
  90. w.CloseHandle(cast(w.Handle)fd);
  91. }
  92. write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  93. bytes_written: i32;
  94. e := w.WriteFile(cast(w.Handle)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
  95. if e == w.FALSE {
  96. err := w.GetLastError();
  97. return 0, cast(Errno)err;
  98. }
  99. return cast(int)bytes_written, ERROR_NONE;
  100. }
  101. read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  102. bytes_read: i32;
  103. e := w.ReadFile(cast(w.Handle)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
  104. if e == w.FALSE {
  105. err := w.GetLastError();
  106. return 0, cast(Errno)err;
  107. }
  108. return cast(int)bytes_read, ERROR_NONE;
  109. }
  110. seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
  111. using w;
  112. w: u32;
  113. match whence {
  114. case 0: w = FILE_BEGIN;
  115. case 1: w = FILE_CURRENT;
  116. case 2: w = FILE_END;
  117. }
  118. hi := cast(i32)(offset>>32);
  119. lo := cast(i32)(offset);
  120. ft := GetFileType(cast(Handle)fd);
  121. if ft == FILE_TYPE_PIPE {
  122. return 0, ERROR_FILE_IS_PIPE;
  123. }
  124. dw_ptr := SetFilePointer(cast(Handle)fd, lo, ^hi, w);
  125. if dw_ptr == INVALID_SET_FILE_POINTER {
  126. err := GetLastError();
  127. return 0, cast(Errno)err;
  128. }
  129. return cast(i64)hi<<32 + cast(i64)dw_ptr, ERROR_NONE;
  130. }
  131. // NOTE(bill): Uses startup to initialize it
  132. stdin := get_std_handle(w.STD_INPUT_HANDLE);
  133. stdout := get_std_handle(w.STD_OUTPUT_HANDLE);
  134. stderr := get_std_handle(w.STD_ERROR_HANDLE);
  135. get_std_handle :: proc(h: int) -> Handle {
  136. fd := w.GetStdHandle(cast(i32)h);
  137. w.SetHandleInformation(fd, w.HANDLE_FLAG_INHERIT, 0);
  138. return cast(Handle)fd;
  139. }
  140. last_write_time :: proc(fd: Handle) -> File_Time {
  141. file_info: w.By_Handle_File_Information;
  142. w.GetFileInformationByHandle(cast(w.Handle)fd, ^file_info);
  143. lo := cast(File_Time)file_info.last_write_time.lo;
  144. hi := cast(File_Time)file_info.last_write_time.hi;
  145. return lo | hi << 32;
  146. }
  147. last_write_time_by_name :: proc(name: string) -> File_Time {
  148. last_write_time: w.Filetime;
  149. data: w.File_Attribute_Data;
  150. buf: [1024]byte;
  151. assert(buf.count > name.count);
  152. copy(buf[..], cast([]byte)name);
  153. if w.GetFileAttributesExA(^buf[0], w.GetFileExInfoStandard, ^data) != 0 {
  154. last_write_time = data.last_write_time;
  155. }
  156. l := cast(File_Time)last_write_time.lo;
  157. h := cast(File_Time)last_write_time.hi;
  158. return l | h << 32;
  159. }
  160. read_entire_file :: proc(name: string) -> ([]byte, bool) {
  161. buf: [300]byte;
  162. copy(buf[..], cast([]byte)name);
  163. fd, err := open(name, O_RDONLY, 0);
  164. if err != ERROR_NONE {
  165. return nil, false;
  166. }
  167. defer close(fd);
  168. length: i64;
  169. file_size_ok := w.GetFileSizeEx(cast(w.Handle)fd, ^length) != 0;
  170. if !file_size_ok {
  171. return nil, false;
  172. }
  173. data := new_slice(u8, length);
  174. if data.data == nil {
  175. return nil, false;
  176. }
  177. single_read_length: i32;
  178. total_read: i64;
  179. for total_read < length {
  180. remaining := length - total_read;
  181. to_read: u32;
  182. MAX :: 1<<32-1;
  183. if remaining <= MAX {
  184. to_read = cast(u32)remaining;
  185. } else {
  186. to_read = MAX;
  187. }
  188. w.ReadFile(cast(w.Handle)fd, ^data[total_read], to_read, ^single_read_length, nil);
  189. if single_read_length <= 0 {
  190. free(data);
  191. return nil, false;
  192. }
  193. total_read += cast(i64)single_read_length;
  194. }
  195. return data, true;
  196. }
  197. heap_alloc :: proc(size: int) -> rawptr {
  198. return w.HeapAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, size);
  199. }
  200. heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
  201. if new_size == 0 {
  202. heap_free(ptr);
  203. return nil;
  204. }
  205. if ptr == nil {
  206. return heap_alloc(new_size);
  207. }
  208. return w.HeapReAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, ptr, new_size);
  209. }
  210. heap_free :: proc(ptr: rawptr) {
  211. if ptr == nil {
  212. return;
  213. }
  214. w.HeapFree(w.GetProcessHeap(), 0, ptr);
  215. }
  216. exit :: proc(code: int) {
  217. w.ExitProcess(cast(u32)code);
  218. }
  219. current_thread_id :: proc() -> int {
  220. return cast(int)w.GetCurrentThreadId();
  221. }