| ... | ... | @@ -6,8 +6,13 @@ |
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include "os.hpp" |
| 9 | #include "buffer.hpp" |
| 10 | #include "heap.hpp" |
| 9 | 11 | #include "util.hpp" |
| 10 | 12 | #include "error.hpp" |
| 13 | #include "util_base.hpp" |
| 14 | #include <stdint.h> |
| 15 | #include <stdio.h> |
| 11 | 16 | |
| 12 | 17 | #if defined(_WIN32) |
| 13 | 18 | |
| ... | ... | @@ -73,6 +78,8 @@ typedef SSIZE_T ssize_t; |
| 73 | 78 | #endif |
| 74 | 79 | |
| 75 | 80 | #if defined(ZIG_OS_WINDOWS) |
| 81 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le); |
| 82 | static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice<uint8_t> utf8); |
| 76 | 83 | static uint64_t windows_perf_freq; |
| 77 | 84 | #elif defined(__MACH__) |
| 78 | 85 | static clock_serv_t macos_calendar_clock; |
| ... | ... | @@ -148,15 +155,21 @@ static void os_spawn_process_windows(ZigList<const char *> &args, Termination *t |
| 148 | 155 | os_windows_create_command_line(&command_line, args); |
| 149 | 156 | |
| 150 | 157 | PROCESS_INFORMATION piProcInfo = {0}; |
| 151 | | STARTUPINFO siStartInfo = {0}; |
| 152 | | siStartInfo.cb = sizeof(STARTUPINFO); |
| 158 | STARTUPINFOW siStartInfo = {0}; |
| 159 | siStartInfo.cb = sizeof(STARTUPINFOW); |
| 153 | 160 | |
| 154 | | const char *exe = args.at(0); |
| 155 | | BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr, |
| 161 | Slice<uint8_t> exe_slice = str(args.at(0)); |
| 162 | auto exe_utf16_slice = Slice<WCHAR>::alloc(exe_slice.len + 1); |
| 163 | exe_utf16_slice.ptr[utf8_to_utf16le(exe_utf16_slice.ptr, exe_slice)] = 0; |
| 164 | |
| 165 | auto command_line_utf16 = Slice<WCHAR>::alloc(buf_len(&command_line) + 1); |
| 166 | command_line_utf16.ptr[utf8_to_utf16le(command_line_utf16.ptr, buf_to_slice(&command_line))] = 0; |
| 167 | |
| 168 | BOOL success = CreateProcessW(exe_utf16_slice.ptr, command_line_utf16.ptr, nullptr, nullptr, TRUE, CREATE_UNICODE_ENVIRONMENT, nullptr, nullptr, |
| 156 | 169 | &siStartInfo, &piProcInfo); |
| 157 | 170 | |
| 158 | 171 | if (!success) { |
| 159 | | zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line)); |
| 172 | zig_panic("CreateProcess failed. exe: %s command_line: %s", args.at(0), buf_ptr(&command_line)); |
| 160 | 173 | } |
| 161 | 174 | |
| 162 | 175 | WaitForSingleObject(piProcInfo.hProcess, INFINITE); |
| ... | ... | @@ -269,11 +282,13 @@ void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { |
| 269 | 282 | |
| 270 | 283 | Error os_path_real(Buf *rel_path, Buf *out_abs_path) { |
| 271 | 284 | #if defined(ZIG_OS_WINDOWS) |
| 272 | | buf_resize(out_abs_path, 4096); |
| 273 | | if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) { |
| 274 | | zig_panic("_fullpath failed"); |
| 285 | PathSpace rel_path_space = slice_to_prefixed_file_w(buf_to_slice(rel_path)); |
| 286 | PathSpace out_abs_path_space; |
| 287 | |
| 288 | if (_wfullpath(&out_abs_path_space.data.items[0], &rel_path_space.data.items[0], PATH_MAX_WIDE) == nullptr) { |
| 289 | zig_panic("_wfullpath failed"); |
| 275 | 290 | } |
| 276 | | buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path))); |
| 291 | utf16le_ptr_to_utf8(out_abs_path, &out_abs_path_space.data.items[0]); |
| 277 | 292 | return ErrorNone; |
| 278 | 293 | #elif defined(ZIG_OS_POSIX) |
| 279 | 294 | buf_resize(out_abs_path, PATH_MAX + 1); |
| ... | ... | @@ -773,7 +788,8 @@ Error os_fetch_file(FILE *f, Buf *out_buf) { |
| 773 | 788 | |
| 774 | 789 | Error os_file_exists(Buf *full_path, bool *result) { |
| 775 | 790 | #if defined(ZIG_OS_WINDOWS) |
| 776 | | *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES; |
| 791 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 792 | *result = GetFileAttributesW(&path_space.data.items[0]) != INVALID_FILE_ATTRIBUTES; |
| 777 | 793 | return ErrorNone; |
| 778 | 794 | #else |
| 779 | 795 | *result = access(buf_ptr(full_path), F_OK) != -1; |
| ... | ... | @@ -1021,7 +1037,12 @@ Error os_exec_process(ZigList<const char *> &args, |
| 1021 | 1037 | } |
| 1022 | 1038 | |
| 1023 | 1039 | Error os_write_file(Buf *full_path, Buf *contents) { |
| 1040 | #if defined(ZIG_OS_WINDOWS) |
| 1041 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 1042 | FILE *f = _wfopen(&path_space.data.items[0], L"wb"); |
| 1043 | #else |
| 1024 | 1044 | FILE *f = fopen(buf_ptr(full_path), "wb"); |
| 1045 | #endif |
| 1025 | 1046 | if (!f) { |
| 1026 | 1047 | zig_panic("os_write_file failed for %s", buf_ptr(full_path)); |
| 1027 | 1048 | } |
| ... | ... | @@ -1056,7 +1077,12 @@ static Error copy_open_files(FILE *src_f, FILE *dest_f) { |
| 1056 | 1077 | Error os_dump_file(Buf *src_path, FILE *dest_file) { |
| 1057 | 1078 | Error err; |
| 1058 | 1079 | |
| 1080 | #if defined(ZIG_OS_WINDOWS) |
| 1081 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| 1082 | FILE *src_f = _wfopen(&path_space.data.items[0], L"rb"); |
| 1083 | #else |
| 1059 | 1084 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); |
| 1085 | #endif |
| 1060 | 1086 | if (!src_f) { |
| 1061 | 1087 | int err = errno; |
| 1062 | 1088 | if (err == ENOENT) { |
| ... | ... | @@ -1173,7 +1199,12 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { |
| 1173 | 1199 | } |
| 1174 | 1200 | |
| 1175 | 1201 | Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1202 | #if defined(ZIG_OS_WINDOWS) |
| 1203 | PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| 1204 | FILE *src_f = _wfopen(&src_path_space.data.items[0], L"rb"); |
| 1205 | #else |
| 1176 | 1206 | FILE *src_f = fopen(buf_ptr(src_path), "rb"); |
| 1207 | #endif |
| 1177 | 1208 | if (!src_f) { |
| 1178 | 1209 | int err = errno; |
| 1179 | 1210 | if (err == ENOENT) { |
| ... | ... | @@ -1184,7 +1215,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1184 | 1215 | return ErrorFileSystem; |
| 1185 | 1216 | } |
| 1186 | 1217 | } |
| 1218 | #if defined(ZIG_OS_WINDOWS) |
| 1219 | PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); |
| 1220 | FILE *dest_f = _wfopen(&dest_path_space.data.items[0], L"wb"); |
| 1221 | #else |
| 1187 | 1222 | FILE *dest_f = fopen(buf_ptr(dest_path), "wb"); |
| 1223 | #endif |
| 1188 | 1224 | if (!dest_f) { |
| 1189 | 1225 | int err = errno; |
| 1190 | 1226 | if (err == ENOENT) { |
| ... | ... | @@ -1205,7 +1241,12 @@ Error os_copy_file(Buf *src_path, Buf *dest_path) { |
| 1205 | 1241 | } |
| 1206 | 1242 | |
| 1207 | 1243 | Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| 1244 | #if defined(ZIG_OS_WINDOWS) |
| 1245 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 1246 | FILE *f = _wfopen(&path_space.data.items[0], L"rb"); |
| 1247 | #else |
| 1208 | 1248 | FILE *f = fopen(buf_ptr(full_path), "rb"); |
| 1249 | #endif |
| 1209 | 1250 | if (!f) { |
| 1210 | 1251 | switch (errno) { |
| 1211 | 1252 | case EACCES: |
| ... | ... | @@ -1230,11 +1271,11 @@ Error os_fetch_file_path(Buf *full_path, Buf *out_contents) { |
| 1230 | 1271 | |
| 1231 | 1272 | Error os_get_cwd(Buf *out_cwd) { |
| 1232 | 1273 | #if defined(ZIG_OS_WINDOWS) |
| 1233 | | char buf[4096]; |
| 1234 | | if (GetCurrentDirectory(4096, buf) == 0) { |
| 1274 | PathSpace path_space; |
| 1275 | if (GetCurrentDirectoryW(PATH_MAX_WIDE, &path_space.data.items[0]) == 0) { |
| 1235 | 1276 | zig_panic("GetCurrentDirectory failed"); |
| 1236 | 1277 | } |
| 1237 | | buf_init_from_str(out_cwd, buf); |
| 1278 | utf16le_ptr_to_utf8(out_cwd, &path_space.data.items[0]); |
| 1238 | 1279 | return ErrorNone; |
| 1239 | 1280 | #elif defined(ZIG_OS_POSIX) |
| 1240 | 1281 | char buf[PATH_MAX]; |
| ... | ... | @@ -1330,7 +1371,9 @@ Error os_rename(Buf *src_path, Buf *dest_path) { |
| 1330 | 1371 | return ErrorNone; |
| 1331 | 1372 | } |
| 1332 | 1373 | #if defined(ZIG_OS_WINDOWS) |
| 1333 | | if (!MoveFileExA(buf_ptr(src_path), buf_ptr(dest_path), MOVEFILE_REPLACE_EXISTING)) { |
| 1374 | PathSpace src_path_space = slice_to_prefixed_file_w(buf_to_slice(src_path)); |
| 1375 | PathSpace dest_path_space = slice_to_prefixed_file_w(buf_to_slice(dest_path)); |
| 1376 | if (!MoveFileExW(&src_path_space.data.items[0], &dest_path_space.data.items[0], MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH)) { |
| 1334 | 1377 | return ErrorFileSystem; |
| 1335 | 1378 | } |
| 1336 | 1379 | #else |
| ... | ... | @@ -1426,7 +1469,15 @@ Error os_make_path(Buf *path) { |
| 1426 | 1469 | |
| 1427 | 1470 | Error os_make_dir(Buf *path) { |
| 1428 | 1471 | #if defined(ZIG_OS_WINDOWS) |
| 1429 | | if (!CreateDirectory(buf_ptr(path), NULL)) { |
| 1472 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(path)); |
| 1473 | if (memEql(buf_to_slice(path), str("C:\\dev\\tést"))) { |
| 1474 | for (size_t i = 0; i < path_space.len; i++) { |
| 1475 | fprintf(stderr, "%d ", path_space.data.items[i]); |
| 1476 | } |
| 1477 | fprintf(stderr, "\n"); |
| 1478 | } |
| 1479 | |
| 1480 | if (!CreateDirectoryW(&path_space.data.items[0], NULL)) { |
| 1430 | 1481 | if (GetLastError() == ERROR_ALREADY_EXISTS) |
| 1431 | 1482 | return ErrorPathAlreadyExists; |
| 1432 | 1483 | if (GetLastError() == ERROR_PATH_NOT_FOUND) |
| ... | ... | @@ -1531,18 +1582,13 @@ int os_init(void) { |
| 1531 | 1582 | |
| 1532 | 1583 | Error os_self_exe_path(Buf *out_path) { |
| 1533 | 1584 | #if defined(ZIG_OS_WINDOWS) |
| 1534 | | buf_resize(out_path, 256); |
| 1535 | | for (;;) { |
| 1536 | | DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path)); |
| 1537 | | if (copied_amt <= 0) { |
| 1538 | | return ErrorFileNotFound; |
| 1539 | | } |
| 1540 | | if (copied_amt < buf_len(out_path)) { |
| 1541 | | buf_resize(out_path, copied_amt); |
| 1542 | | return ErrorNone; |
| 1543 | | } |
| 1544 | | buf_resize(out_path, buf_len(out_path) * 2); |
| 1585 | PathSpace path_space; |
| 1586 | DWORD copied_amt = GetModuleFileNameW(nullptr, &path_space.data.items[0], PATH_MAX_WIDE); |
| 1587 | if (copied_amt <= 0) { |
| 1588 | return ErrorFileNotFound; |
| 1545 | 1589 | } |
| 1590 | utf16le_ptr_to_utf8(out_path, &path_space.data.items[0]); |
| 1591 | return ErrorNone; |
| 1546 | 1592 | |
| 1547 | 1593 | #elif defined(ZIG_OS_DARWIN) |
| 1548 | 1594 | // How long is the executable's path? |
| ... | ... | @@ -1719,6 +1765,15 @@ static uint8_t utf8CodepointSequenceLength(uint32_t c) { |
| 1719 | 1765 | zig_unreachable(); |
| 1720 | 1766 | } |
| 1721 | 1767 | |
| 1768 | // Ported from std.unicode.utf8ByteSequenceLength |
| 1769 | static uint8_t utf8ByteSequenceLength(uint8_t first_byte) { |
| 1770 | if (first_byte < 0b10000000) return 1; |
| 1771 | if ((first_byte & 0b11100000) == 0b11000000) return 2; |
| 1772 | if ((first_byte & 0b11110000) == 0b11100000) return 3; |
| 1773 | if ((first_byte & 0b11111000) == 0b11110000) return 4; |
| 1774 | zig_unreachable(); |
| 1775 | } |
| 1776 | |
| 1722 | 1777 | // Ported from std/unicode.zig |
| 1723 | 1778 | static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1724 | 1779 | size_t length = utf8CodepointSequenceLength(c); |
| ... | ... | @@ -1753,6 +1808,80 @@ static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) { |
| 1753 | 1808 | return length; |
| 1754 | 1809 | } |
| 1755 | 1810 | |
| 1811 | // Ported from std.unicode.utf8Decode2 |
| 1812 | static uint32_t utf8Decode2(Slice<uint8_t> bytes) { |
| 1813 | assert(bytes.len == 2); |
| 1814 | assert((bytes.at(0) & 0b11100000) == 0b11000000); |
| 1815 | |
| 1816 | uint32_t value = bytes.at(0) & 0b00011111; |
| 1817 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| 1818 | value <<= 6; |
| 1819 | value |= bytes.at(1) & 0b00111111; |
| 1820 | |
| 1821 | assert(value >= 0x80); |
| 1822 | return value; |
| 1823 | } |
| 1824 | |
| 1825 | // Ported from std.unicode.utf8Decode3 |
| 1826 | static uint32_t utf8Decode3(Slice<uint8_t> bytes) { |
| 1827 | assert(bytes.len == 3); |
| 1828 | assert((bytes.at(0) & 0b11110000) == 0b11100000); |
| 1829 | |
| 1830 | uint32_t value = bytes.at(0) & 0b00001111; |
| 1831 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| 1832 | value <<= 6; |
| 1833 | value |= bytes.at(1) & 0b00111111; |
| 1834 | |
| 1835 | assert((bytes.at(2) & 0b11000000) == 0b10000000); |
| 1836 | value <<= 6; |
| 1837 | value |= bytes.at(2) & 0b00111111; |
| 1838 | |
| 1839 | assert(value >= 0x80); |
| 1840 | assert(value < 0xd800 || value > 0xdfff); |
| 1841 | return value; |
| 1842 | } |
| 1843 | |
| 1844 | // Ported from std.unicode.utf8Decode4 |
| 1845 | static uint32_t utf8Decode4(Slice<uint8_t> bytes) { |
| 1846 | assert(bytes.len == 4); |
| 1847 | assert((bytes.at(0) & 0b11111000) == 0b11110000); |
| 1848 | |
| 1849 | uint32_t value = bytes.at(0) & 0b00000111; |
| 1850 | assert((bytes.at(1) & 0b11000000) == 0b10000000); |
| 1851 | value <<= 6; |
| 1852 | value |= bytes.at(1) & 0b00111111; |
| 1853 | |
| 1854 | assert((bytes.at(2) & 0b11000000) == 0b10000000); |
| 1855 | value <<= 6; |
| 1856 | value |= bytes.at(2) & 0b00111111; |
| 1857 | |
| 1858 | assert((bytes.at(3) & 0b11000000) == 0b10000000); |
| 1859 | value <<= 6; |
| 1860 | value |= bytes.at(3) & 0b00111111; |
| 1861 | |
| 1862 | assert(value >= 0x10000 && value <= 0x10FFFF); |
| 1863 | return value; |
| 1864 | } |
| 1865 | |
| 1866 | // Ported from std.unicode.utf8Decode |
| 1867 | static uint32_t utf8Decode(Slice<uint8_t> bytes) { |
| 1868 | switch (bytes.len) { |
| 1869 | case 1: |
| 1870 | return bytes.at(0); |
| 1871 | break; |
| 1872 | case 2: |
| 1873 | return utf8Decode2(bytes); |
| 1874 | break; |
| 1875 | case 3: |
| 1876 | return utf8Decode3(bytes); |
| 1877 | break; |
| 1878 | case 4: |
| 1879 | return utf8Decode4(bytes); |
| 1880 | break; |
| 1881 | default: |
| 1882 | zig_unreachable(); |
| 1883 | } |
| 1884 | } |
| 1756 | 1885 | // Ported from std.unicode.utf16leToUtf8Alloc |
| 1757 | 1886 | static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1758 | 1887 | // optimistically guess that it will all be ascii. |
| ... | ... | @@ -1770,6 +1899,60 @@ static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) { |
| 1770 | 1899 | out_index += utf8_len; |
| 1771 | 1900 | } |
| 1772 | 1901 | } |
| 1902 | |
| 1903 | // Ported from std.unicode.utf8ToUtf16Le |
| 1904 | static size_t utf8_to_utf16le(WCHAR *utf16_le, Slice<uint8_t> utf8) { |
| 1905 | size_t dest_i = 0; |
| 1906 | size_t src_i = 0; |
| 1907 | while (src_i < utf8.len) { |
| 1908 | uint8_t n = utf8ByteSequenceLength(utf8.at(src_i)); |
| 1909 | size_t next_src_i = src_i + n; |
| 1910 | uint32_t codepoint = utf8Decode(utf8.slice(src_i, next_src_i)); |
| 1911 | if (codepoint < 0x10000) { |
| 1912 | utf16_le[dest_i] = codepoint; |
| 1913 | dest_i += 1; |
| 1914 | } else { |
| 1915 | WCHAR high = ((codepoint - 0x10000) >> 10) + 0xD800; |
| 1916 | WCHAR low = (codepoint & 0x3FF) + 0xDC00; |
| 1917 | utf16_le[dest_i] = high; |
| 1918 | utf16_le[dest_i + 1] = low; |
| 1919 | dest_i += 2; |
| 1920 | } |
| 1921 | src_i = next_src_i; |
| 1922 | } |
| 1923 | return dest_i; |
| 1924 | } |
| 1925 | |
| 1926 | // Ported from std.os.windows.sliceToPrefixedFileW |
| 1927 | PathSpace slice_to_prefixed_file_w(Slice<uint8_t> path) { |
| 1928 | PathSpace path_space; |
| 1929 | for (size_t idx = 0; idx < path.len; idx++) { |
| 1930 | assert(path.ptr[idx] != '*' && path.ptr[idx] != '?' && path.ptr[idx] != '"' && |
| 1931 | path.ptr[idx] != '<' && path.ptr[idx] != '>' && path.ptr[idx] != '|'); |
| 1932 | } |
| 1933 | |
| 1934 | size_t start_index; |
| 1935 | if (memStartsWith(path, str("\\?")) || !isAbsoluteWindows(path)) { |
| 1936 | start_index = 0; |
| 1937 | } else { |
| 1938 | static WCHAR prefix[4] = { u'\\', u'?', u'?', u'\\' }; |
| 1939 | memCopy(path_space.data.slice(), Slice<WCHAR> { prefix, 4 }); |
| 1940 | start_index = 4; |
| 1941 | } |
| 1942 | |
| 1943 | path_space.len = start_index + utf8_to_utf16le(path_space.data.slice().sliceFrom(start_index).ptr, path); |
| 1944 | assert(path_space.len <= path_space.data.len); |
| 1945 | |
| 1946 | Slice<WCHAR> path_slice = path_space.data.slice().slice(0, path_space.len); |
| 1947 | for (size_t elem_idx = 0; elem_idx < path_slice.len; elem_idx += 1) { |
| 1948 | if (path_slice.at(elem_idx) == '/') { |
| 1949 | path_slice.at(elem_idx) = '\\'; |
| 1950 | } |
| 1951 | } |
| 1952 | |
| 1953 | path_space.data.items[path_space.len] = 0; |
| 1954 | return path_space; |
| 1955 | } |
| 1773 | 1956 | #endif |
| 1774 | 1957 | |
| 1775 | 1958 | // Ported from std.os.getAppDataDir |
| ... | ... | @@ -1862,8 +2045,8 @@ Error os_self_exe_shared_libs(ZigList<Buf *> &paths) { |
| 1862 | 2045 | |
| 1863 | 2046 | Error os_file_open_rw(Buf *full_path, OsFile *out_file, OsFileAttr *attr, bool need_write, uint32_t mode) { |
| 1864 | 2047 | #if defined(ZIG_OS_WINDOWS) |
| 1865 | | // TODO use CreateFileW |
| 1866 | | HANDLE result = CreateFileA(buf_ptr(full_path), |
| 2048 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 2049 | HANDLE result = CreateFileW(&path_space.data.items[0], |
| 1867 | 2050 | need_write ? (GENERIC_READ|GENERIC_WRITE) : GENERIC_READ, |
| 1868 | 2051 | need_write ? 0 : FILE_SHARE_READ, |
| 1869 | 2052 | nullptr, |
| ... | ... | @@ -1967,8 +2150,9 @@ Error os_file_open_w(Buf *full_path, OsFile *out_file, OsFileAttr *attr, uint32_ |
| 1967 | 2150 | |
| 1968 | 2151 | Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) { |
| 1969 | 2152 | #if defined(ZIG_OS_WINDOWS) |
| 2153 | PathSpace path_space = slice_to_prefixed_file_w(buf_to_slice(full_path)); |
| 1970 | 2154 | for (;;) { |
| 1971 | | HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE, |
| 2155 | HANDLE result = CreateFileW(&path_space.data.items[0], GENERIC_READ | GENERIC_WRITE, |
| 1972 | 2156 | 0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); |
| 1973 | 2157 | |
| 1974 | 2158 | if (result == INVALID_HANDLE_VALUE) { |