os_windows.odin 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // +build windows
  2. package os
  3. import "core:sys/win32"
  4. OS :: "windows";
  5. Handle :: distinct uintptr;
  6. File_Time :: distinct u64;
  7. Errno :: distinct int;
  8. INVALID_HANDLE :: ~Handle(0);
  9. O_RDONLY :: 0x00000;
  10. O_WRONLY :: 0x00001;
  11. O_RDWR :: 0x00002;
  12. O_CREATE :: 0x00040;
  13. O_EXCL :: 0x00080;
  14. O_NOCTTY :: 0x00100;
  15. O_TRUNC :: 0x00200;
  16. O_NONBLOCK :: 0x00800;
  17. O_APPEND :: 0x00400;
  18. O_SYNC :: 0x01000;
  19. O_ASYNC :: 0x02000;
  20. O_CLOEXEC :: 0x80000;
  21. ERROR_NONE: Errno : 0;
  22. ERROR_FILE_NOT_FOUND: Errno : 2;
  23. ERROR_PATH_NOT_FOUND: Errno : 3;
  24. ERROR_ACCESS_DENIED: Errno : 5;
  25. ERROR_NO_MORE_FILES: Errno : 18;
  26. ERROR_HANDLE_EOF: Errno : 38;
  27. ERROR_NETNAME_DELETED: Errno : 64;
  28. ERROR_FILE_EXISTS: Errno : 80;
  29. ERROR_BROKEN_PIPE: Errno : 109;
  30. ERROR_BUFFER_OVERFLOW: Errno : 111;
  31. ERROR_INSUFFICIENT_BUFFER: Errno : 122;
  32. ERROR_MOD_NOT_FOUND: Errno : 126;
  33. ERROR_PROC_NOT_FOUND: Errno : 127;
  34. ERROR_DIR_NOT_EMPTY: Errno : 145;
  35. ERROR_ALREADY_EXISTS: Errno : 183;
  36. ERROR_ENVVAR_NOT_FOUND: Errno : 203;
  37. ERROR_MORE_DATA: Errno : 234;
  38. ERROR_OPERATION_ABORTED: Errno : 995;
  39. ERROR_IO_PENDING: Errno : 997;
  40. ERROR_NOT_FOUND: Errno : 1168;
  41. ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
  42. WSAEACCES: Errno : 10013;
  43. WSAECONNRESET: Errno : 10054;
  44. // Windows reserves errors >= 1<<29 for application use
  45. ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
  46. // "Argv" arguments converted to Odin strings
  47. args := _alloc_command_line_arguments();
  48. open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
  49. if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
  50. access: u32;
  51. switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
  52. case O_RDONLY: access = win32.FILE_GENERIC_READ;
  53. case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
  54. case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
  55. }
  56. if mode&O_CREATE != 0 {
  57. access |= win32.FILE_GENERIC_WRITE;
  58. }
  59. if mode&O_APPEND != 0 {
  60. access &~= win32.FILE_GENERIC_WRITE;
  61. access |= win32.FILE_APPEND_DATA;
  62. }
  63. share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
  64. sa: ^win32.Security_Attributes = nil;
  65. sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true};
  66. if mode&O_CLOEXEC == 0 {
  67. sa = &sa_inherit;
  68. }
  69. create_mode: u32;
  70. switch {
  71. case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
  72. create_mode = win32.CREATE_NEW;
  73. case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
  74. create_mode = win32.CREATE_ALWAYS;
  75. case mode&O_CREATE == O_CREATE:
  76. create_mode = win32.OPEN_ALWAYS;
  77. case mode&O_TRUNC == O_TRUNC:
  78. create_mode = win32.TRUNCATE_EXISTING;
  79. case:
  80. create_mode = win32.OPEN_EXISTING;
  81. }
  82. wide_path := win32.utf8_to_wstring(path);
  83. handle := Handle(win32.create_file_w(wide_path, access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
  84. if handle != INVALID_HANDLE do return handle, ERROR_NONE;
  85. err := Errno(win32.get_last_error());
  86. return INVALID_HANDLE, err;
  87. }
  88. close :: proc(fd: Handle) {
  89. win32.close_handle(win32.Handle(fd));
  90. }
  91. write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  92. if len(data) == 0 do return 0, ERROR_NONE;
  93. single_write_length: i32;
  94. total_write: i64;
  95. length := i64(len(data));
  96. for total_write < length {
  97. remaining := length - total_write;
  98. MAX :: 1<<31-1;
  99. to_write: i32 = min(i32(remaining), MAX);
  100. e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
  101. if single_write_length <= 0 || !e {
  102. err := Errno(win32.get_last_error());
  103. return int(total_write), err;
  104. }
  105. total_write += i64(single_write_length);
  106. }
  107. return int(total_write), ERROR_NONE;
  108. }
  109. read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  110. if len(data) == 0 do return 0, ERROR_NONE;
  111. single_read_length: i32;
  112. total_read: i64;
  113. length := i64(len(data));
  114. for total_read < length {
  115. remaining := length - total_read;
  116. MAX :: 1<<32-1;
  117. to_read: u32 = min(u32(remaining), MAX);
  118. e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
  119. if single_read_length <= 0 || !e {
  120. err := Errno(win32.get_last_error());
  121. return int(total_read), err;
  122. }
  123. total_read += i64(single_read_length);
  124. }
  125. return int(total_read), ERROR_NONE;
  126. }
  127. seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
  128. w: u32;
  129. switch whence {
  130. case 0: w = win32.FILE_BEGIN;
  131. case 1: w = win32.FILE_CURRENT;
  132. case 2: w = win32.FILE_END;
  133. }
  134. hi := i32(offset>>32);
  135. lo := i32(offset);
  136. ft := win32.get_file_type(win32.Handle(fd));
  137. if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
  138. dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
  139. if dw_ptr == win32.INVALID_SET_FILE_POINTER {
  140. err := Errno(win32.get_last_error());
  141. return 0, err;
  142. }
  143. return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
  144. }
  145. file_size :: proc(fd: Handle) -> (i64, Errno) {
  146. length: i64;
  147. err: Errno;
  148. if !win32.get_file_size_ex(win32.Handle(fd), &length) {
  149. err = Errno(win32.get_last_error());
  150. }
  151. return length, err;
  152. }
  153. // NOTE(bill): Uses startup to initialize it
  154. stdin := get_std_handle(win32.STD_INPUT_HANDLE);
  155. stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
  156. stderr := get_std_handle(win32.STD_ERROR_HANDLE);
  157. get_std_handle :: proc(h: int) -> Handle {
  158. fd := win32.get_std_handle(i32(h));
  159. win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
  160. return Handle(fd);
  161. }
  162. last_write_time :: proc(fd: Handle) -> File_Time {
  163. file_info: win32.By_Handle_File_Information;
  164. win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
  165. lo := File_Time(file_info.last_write_time.lo);
  166. hi := File_Time(file_info.last_write_time.hi);
  167. return lo | hi << 32;
  168. }
  169. last_write_time_by_name :: proc(name: string) -> File_Time {
  170. last_write_time: win32.Filetime;
  171. data: win32.File_Attribute_Data;
  172. wide_path := win32.utf8_to_wstring(name);
  173. if win32.get_file_attributes_ex_w(wide_path, win32.GetFileExInfoStandard, &data) {
  174. last_write_time = data.last_write_time;
  175. }
  176. l := File_Time(last_write_time.lo);
  177. h := File_Time(last_write_time.hi);
  178. return l | h << 32;
  179. }
  180. heap_alloc :: proc(size: int) -> rawptr {
  181. return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
  182. }
  183. heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
  184. if new_size == 0 {
  185. heap_free(ptr);
  186. return nil;
  187. }
  188. if ptr == nil do return heap_alloc(new_size);
  189. return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
  190. }
  191. heap_free :: proc(ptr: rawptr) {
  192. if ptr == nil do return;
  193. win32.heap_free(win32.get_process_heap(), 0, ptr);
  194. }
  195. exit :: proc(code: int) -> ! {
  196. win32.exit_process(u32(code));
  197. }
  198. current_thread_id :: proc "contextless" () -> int {
  199. return int(win32.get_current_thread_id());
  200. }
  201. _alloc_command_line_arguments :: proc() -> []string {
  202. arg_count: i32;
  203. arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
  204. arg_list := make([]string, int(arg_count));
  205. for _, i in arg_list {
  206. wc_str := (^win32.Wstring)(uintptr(arg_list_ptr) + size_of(win32.Wstring)*uintptr(i))^;
  207. olen := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
  208. nil, 0, nil, nil);
  209. buf := make([]byte, int(olen));
  210. n := win32.wide_char_to_multi_byte(win32.CP_UTF8, 0, wc_str, -1,
  211. cstring(&buf[0]), olen, nil, nil);
  212. if n > 0 {
  213. n -= 1;
  214. }
  215. arg_list[i] = string(buf[:n]);
  216. }
  217. return arg_list;
  218. }