From eef44b11f3b26cde6086251ce1b9f661557e4d5c Mon Sep 17 00:00:00 2001 From: gingerBill Date: Thu, 12 May 2022 13:17:58 +0100 Subject: [PATCH] Make the utf16 conversion procedures in `core:sys/windows` safer by checking for memory leaks --- core/os/dir_windows.odin | 2 +- core/os/env_windows.odin | 4 +-- core/os/file_windows.odin | 2 +- core/os/os2/env_windows.odin | 4 +-- core/os/os2/file.odin | 18 ++++++++++++ core/os/os2/file_stream.odin | 10 ++++++- core/os/os2/file_windows.odin | 12 ++++---- core/os/os2/stat_windows.odin | 14 ++++----- core/os/os2/temp_file.odin | 2 +- core/os/os2/temp_file_windows.odin | 4 +-- core/os/stat_windows.odin | 6 ++-- core/sys/win32/comdlg32.odin | 2 +- core/sys/win32/crt.odin | 2 +- core/sys/win32/general.odin | 18 ++++++------ core/sys/win32/tests/general.odin | 46 +++++++++++++++--------------- core/sys/windows/kernel32.odin | 5 ++++ core/sys/windows/util.odin | 26 ++++++++--------- 17 files changed, 105 insertions(+), 72 deletions(-) diff --git a/core/os/dir_windows.odin b/core/os/dir_windows.odin index 3261b8cb3..89a09d403 100644 --- a/core/os/dir_windows.odin +++ b/core/os/dir_windows.odin @@ -13,7 +13,7 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F if d.cFileName[0] == '.' && d.cFileName[1] == '.' && d.cFileName[2] == 0 { return } - path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:])}) + path := strings.concatenate({base_path, `\`, win32.utf16_to_utf8(d.cFileName[:]) or_else ""}) fi.fullpath = path fi.name = basename(path) fi.size = i64(d.nFileSizeHigh)<<32 + i64(d.nFileSizeLow) diff --git a/core/os/env_windows.odin b/core/os/env_windows.odin index 74981bc6e..9a33a0611 100644 --- a/core/os/env_windows.odin +++ b/core/os/env_windows.odin @@ -22,7 +22,7 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin } if n <= u32(len(b)) { - value = win32.utf16_to_utf8(b[:n], allocator) + value, _ = win32.utf16_to_utf8(b[:n], allocator) found = true return } @@ -76,7 +76,7 @@ environ :: proc(allocator := context.allocator) -> []string { if i <= from { break } - append(&r, win32.utf16_to_utf8(envs[from:i], allocator)) + append(&r, win32.utf16_to_utf8(envs[from:i], allocator) or_else "") from = i + 1 } } diff --git a/core/os/file_windows.odin b/core/os/file_windows.odin index a9f78070f..daabe60f0 100644 --- a/core/os/file_windows.odin +++ b/core/os/file_windows.odin @@ -365,7 +365,7 @@ get_current_directory :: proc(allocator := context.allocator) -> string { win32.ReleaseSRWLockExclusive(&cwd_lock) - return win32.utf16_to_utf8(dir_buf_wstr, allocator) + return win32.utf16_to_utf8(dir_buf_wstr, allocator) or_else "" } set_current_directory :: proc(path: string) -> (err: Errno) { diff --git a/core/os/os2/env_windows.odin b/core/os/os2/env_windows.odin index 52c6c0f55..f58922fac 100644 --- a/core/os/os2/env_windows.odin +++ b/core/os/os2/env_windows.odin @@ -29,7 +29,7 @@ _lookup_env :: proc(key: string, allocator: runtime.Allocator) -> (value: string return "", false } - value = win32.utf16_to_utf8(b[:n], allocator) + value = win32.utf16_to_utf8(b[:n], allocator) or_else "" found = true return } @@ -73,7 +73,7 @@ _environ :: proc(allocator: runtime.Allocator) -> []string { break } w := ([^]u16)(p)[from:i] - append(&r, win32.utf16_to_utf8(w, allocator)) + append(&r, win32.utf16_to_utf8(w, allocator) or_else "") from = i + 1 } } diff --git a/core/os/os2/file.odin b/core/os/os2/file.odin index 268631dd6..4b271b9ea 100644 --- a/core/os/os2/file.odin +++ b/core/os/os2/file.odin @@ -21,6 +21,7 @@ File_Mode_Device :: File_Mode(1<<18) File_Mode_Char_Device :: File_Mode(1<<19) File_Mode_Sym_Link :: File_Mode(1<<20) +File_Mode_Perm :: File_Mode(0o777) // Unix permision bits File_Flags :: distinct bit_set[File_Flag; uint] File_Flag :: enum { @@ -194,3 +195,20 @@ is_dir :: proc(path: string) -> bool { return _is_dir(path) } + +copy_file :: proc(dst_path, src_path: string) -> Error { + src := open(src_path) or_return + defer close(src) + + info := fstat(src, _file_allocator()) or_return + defer file_info_delete(info, _file_allocator()) + if info.is_dir { + return .Invalid_File + } + + dst := open(dst_path, {.Read, .Write, .Create, .Trunc}, info.mode & File_Mode_Perm) or_return + defer close(dst) + + _, err := io.copy(to_writer(dst), to_reader(src)) + return err +} \ No newline at end of file diff --git a/core/os/os2/file_stream.odin b/core/os/os2/file_stream.odin index 7b68d0e21..5e3db9370 100644 --- a/core/os/os2/file_stream.odin +++ b/core/os/os2/file_stream.odin @@ -2,12 +2,20 @@ package os2 import "core:io" -file_to_stream :: proc(f: ^File) -> (s: io.Stream) { +to_stream :: proc(f: ^File) -> (s: io.Stream) { s.stream_data = f s.stream_vtable = _file_stream_vtable return } +to_writer :: proc(f: ^File) -> (s: io.Writer) { + return {to_stream(f)} +} +to_reader :: proc(f: ^File) -> (s: io.Reader) { + return {to_stream(f)} +} + + @(private) error_to_io_error :: proc(ferr: Error) -> io.Error { if ferr == nil { diff --git a/core/os/os2/file_windows.odin b/core/os/os2/file_windows.odin index b9ebfe10e..7589ed799 100644 --- a/core/os/os2/file_windows.odin +++ b/core/os/os2/file_windows.odin @@ -529,16 +529,16 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st } if !has_unc_prefix(p) { - return win32.utf16_to_utf8(p, allocator), nil + return win32.utf16_to_utf8(p, allocator) } ws := p[4:] switch { case len(ws) >= 2 && ws[1] == ':': - return win32.utf16_to_utf8(ws, allocator), nil + return win32.utf16_to_utf8(ws, allocator) case has_prefix(ws, `UNC\`): ws[3] = '\\' // override data in buffer - return win32.utf16_to_utf8(ws[3:], allocator), nil + return win32.utf16_to_utf8(ws[3:], allocator) } @@ -560,9 +560,9 @@ _normalize_link_path :: proc(p: []u16, allocator: runtime.Allocator) -> (str: st ws = ws[4:] if len(ws) > 3 && has_prefix(ws, `UNC`) { ws[2] = '\\' - return win32.utf16_to_utf8(ws[2:], allocator), nil + return win32.utf16_to_utf8(ws[2:], allocator) } - return win32.utf16_to_utf8(ws, allocator), nil + return win32.utf16_to_utf8(ws, allocator) } return "", .Invalid_Path } @@ -593,7 +593,7 @@ _read_link :: proc(name: string, allocator: runtime.Allocator) -> (s: string, er pb[rb.SubstituteNameOffset+rb.SubstituteNameLength] = 0 p := pb[rb.SubstituteNameOffset:][:rb.SubstituteNameLength] if rb.Flags & win32.SYMLINK_FLAG_RELATIVE != 0 { - return win32.utf16_to_utf8(p, allocator), nil + return win32.utf16_to_utf8(p, allocator) } return _normalize_link_path(p, allocator) diff --git a/core/os/os2/stat_windows.odin b/core/os/os2/stat_windows.odin index 603343a18..5de5269d7 100644 --- a/core/os/os2/stat_windows.odin +++ b/core/os/os2/stat_windows.odin @@ -57,7 +57,7 @@ full_path_from_name :: proc(name: string, allocator: runtime.Allocator) -> (path if n == 0 { return "", _get_platform_error() } - return win32.utf16_to_utf8(buf[:n], allocator), nil + return win32.utf16_to_utf8(buf[:n], allocator) } @@ -131,7 +131,7 @@ _cleanpath_from_handle :: proc(f: ^File, allocator: runtime.Allocator) -> (strin } buf := make([]u16, max(n, 260)+1, _temp_allocator()) n = win32.GetFinalPathNameByHandleW(h, raw_data(buf), u32(len(buf)), 0) - return _cleanpath_from_buf(buf[:n], allocator), nil + return _cleanpath_from_buf(buf[:n], allocator) } _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { @@ -149,7 +149,7 @@ _cleanpath_from_handle_u16 :: proc(f: ^File) -> ([]u16, Error) { return _cleanpath_strip_prefix(buf[:n]), nil } -_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> string { +_cleanpath_from_buf :: proc(buf: []u16, allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { buf := buf buf = _cleanpath_strip_prefix(buf) return win32.utf16_to_utf8(buf, allocator) @@ -194,15 +194,15 @@ file_type_mode :: proc(h: win32.HANDLE) -> File_Mode { -_file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) { - if FileAttributes & win32.FILE_ATTRIBUTE_READONLY != 0 { +_file_mode_from_file_attributes :: proc(file_attributes: win32.DWORD, h: win32.HANDLE, ReparseTag: win32.DWORD) -> (mode: File_Mode) { + if file_attributes & win32.FILE_ATTRIBUTE_READONLY != 0 { mode |= 0o444 } else { mode |= 0o666 } is_sym := false - if FileAttributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { + if file_attributes & win32.FILE_ATTRIBUTE_REPARSE_POINT == 0 { is_sym = false } else { is_sym = ReparseTag == win32.IO_REPARSE_TAG_SYMLINK || ReparseTag == win32.IO_REPARSE_TAG_MOUNT_POINT @@ -211,7 +211,7 @@ _file_mode_from_file_attributes :: proc(FileAttributes: win32.DWORD, h: win32.HA if is_sym { mode |= File_Mode_Sym_Link } else { - if FileAttributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { + if file_attributes & win32.FILE_ATTRIBUTE_DIRECTORY != 0 { mode |= 0o111 | File_Mode_Dir } diff --git a/core/os/os2/temp_file.odin b/core/os/os2/temp_file.odin index faf176de1..b05c186a0 100644 --- a/core/os/os2/temp_file.odin +++ b/core/os/os2/temp_file.odin @@ -10,6 +10,6 @@ mkdir_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (strin return _mkdir_temp(dir, pattern, allocator) } -temp_dir :: proc(allocator: runtime.Allocator) -> string { +temp_dir :: proc(allocator: runtime.Allocator) -> (string, Error) { return _temp_dir(allocator) } diff --git a/core/os/os2/temp_file_windows.odin b/core/os/os2/temp_file_windows.odin index a7587988b..08837f7f0 100644 --- a/core/os/os2/temp_file_windows.odin +++ b/core/os/os2/temp_file_windows.odin @@ -12,10 +12,10 @@ _mkdir_temp :: proc(dir, pattern: string, allocator: runtime.Allocator) -> (stri return "", nil } -_temp_dir :: proc(allocator: runtime.Allocator) -> string { +_temp_dir :: proc(allocator: runtime.Allocator) -> (string, runtime.Allocator_Error) { n := win32.GetTempPathW(0, nil) if n == 0 { - return "" + return "", nil } b := make([]u16, max(win32.MAX_PATH, n), _temp_allocator()) n = win32.GetTempPathW(u32(len(b)), raw_data(b)) diff --git a/core/os/stat_windows.odin b/core/os/stat_windows.odin index 5da925560..79bb8c42e 100644 --- a/core/os/stat_windows.odin +++ b/core/os/stat_windows.odin @@ -20,7 +20,7 @@ full_path_from_name :: proc(name: string, allocator := context.allocator) -> (pa return "", Errno(win32.GetLastError()) } if n <= u32(len(buf)) { - return win32.utf16_to_utf8(buf[:n], allocator), ERROR_NONE + return win32.utf16_to_utf8(buf[:n], allocator) or_else "", ERROR_NONE } resize(&buf, len(buf)*2) } @@ -136,7 +136,7 @@ cleanpath_from_handle :: proc(fd: Handle) -> (string, Errno) { if err != 0 { return "", err } - return win32.utf16_to_utf8(buf, context.allocator), err + return win32.utf16_to_utf8(buf, context.allocator) or_else "", err } @(private) cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { @@ -157,7 +157,7 @@ cleanpath_from_handle_u16 :: proc(fd: Handle) -> ([]u16, Errno) { cleanpath_from_buf :: proc(buf: []u16) -> string { buf := buf buf = cleanpath_strip_prefix(buf) - return win32.utf16_to_utf8(buf, context.allocator) + return win32.utf16_to_utf8(buf, context.allocator) or_else "" } @(private) diff --git a/core/sys/win32/comdlg32.odin b/core/sys/win32/comdlg32.odin index 1e0d5c3ca..815def7b6 100644 --- a/core/sys/win32/comdlg32.odin +++ b/core/sys/win32/comdlg32.odin @@ -126,7 +126,7 @@ _open_file_dialog :: proc(title: string, dir: string, } - file_name := utf16_to_utf8(file_buf[:], allocator) + file_name, _ := utf16_to_utf8(file_buf[:], allocator) path = strings.trim_right_null(file_name) return } diff --git a/core/sys/win32/crt.odin b/core/sys/win32/crt.odin index b39d35375..8584a27be 100644 --- a/core/sys/win32/crt.odin +++ b/core/sys/win32/crt.odin @@ -10,6 +10,6 @@ foreign { get_cwd :: proc(allocator := context.temp_allocator) -> string { buffer := make([]u16, MAX_PATH_WIDE, allocator) _get_cwd_wide(Wstring(&buffer[0]), MAX_PATH_WIDE) - file := utf16_to_utf8(buffer[:], allocator) + file, _ := utf16_to_utf8(buffer[:], allocator) return strings.trim_right_null(file) } diff --git a/core/sys/win32/general.odin b/core/sys/win32/general.odin index 1baad8b11..64ee952ce 100644 --- a/core/sys/win32/general.odin +++ b/core/sys/win32/general.odin @@ -1,6 +1,8 @@ // +build windows package win32 +import "core:runtime" + Uint_Ptr :: distinct uintptr Int_Ptr :: distinct int Long_Ptr :: distinct int @@ -858,14 +860,14 @@ utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> Wstri return nil } -wstring_to_utf8 :: proc(s: Wstring, N: int, allocator := context.temp_allocator) -> string { +wstring_to_utf8 :: proc(s: Wstring, N: int, allocator := context.temp_allocator) -> (str: string, err: runtime.Allocator_Error) { if N == 0 { - return "" + return } n := wide_char_to_multi_byte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil) if n == 0 { - return "" + return } // If N == -1 the call to wide_char_to_multi_byte assume the wide string is null terminated @@ -873,11 +875,11 @@ wstring_to_utf8 :: proc(s: Wstring, N: int, allocator := context.temp_allocator) // also null terminated. // If N != -1 it assumes the wide string is not null terminated and the resulting string // will not be null terminated, we therefore have to force it to be null terminated manually. - text := make([]byte, n+1 if N != -1 else n, allocator) + text := make([]byte, n+1 if N != -1 else n, allocator) or_return if n1 := wide_char_to_multi_byte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), cstring(&text[0]), n, nil, nil); n1 == 0 { delete(text, allocator) - return "" + return "", nil } for i in 0.. string { +utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> (string, runtime.Allocator_Error) { if len(s) == 0 { - return "" + return "", nil } return wstring_to_utf8(cast(Wstring)&s[0], len(s), allocator) } diff --git a/core/sys/win32/tests/general.odin b/core/sys/win32/tests/general.odin index 1a5fc911a..9a78dec11 100644 --- a/core/sys/win32/tests/general.odin +++ b/core/sys/win32/tests/general.odin @@ -1,41 +1,41 @@ package win32_tests -import "core:sys/win32" +import win32 "core:sys/windows" import "core:testing" utf16_to_utf8 :: proc(t: ^testing.T, str: []u16, comparison: string, expected_result: bool, loc := #caller_location) { - result := win32.utf16_to_utf8(str[:]); - testing.expect(t, (result == comparison) == expected_result, "Incorrect utf16_to_utf8 conversion", loc); + result, _ := win32.utf16_to_utf8(str[:]) + testing.expect(t, (result == comparison) == expected_result, "Incorrect utf16_to_utf8 conversion", loc) } wstring_to_utf8 :: proc(t: ^testing.T, str: []u16, comparison: string, expected_result: bool, loc := #caller_location) { - result := win32.wstring_to_utf8(nil if len(str) == 0 else cast(win32.Wstring)&str[0], -1); - testing.expect(t, (result == comparison) == expected_result, "Incorrect wstring_to_utf8 conversion", loc); + result, _ := win32.wstring_to_utf8(nil if len(str) == 0 else cast(win32.Wstring)&str[0], -1) + testing.expect(t, (result == comparison) == expected_result, "Incorrect wstring_to_utf8 conversion", loc) } @test test_utf :: proc(t: ^testing.T) { - utf16_to_utf8(t, []u16{}, "", true); - utf16_to_utf8(t, []u16{0}, "", true); - utf16_to_utf8(t, []u16{0, 't', 'e', 's', 't'}, "", true); - utf16_to_utf8(t, []u16{0, 't', 'e', 's', 't', 0}, "", true); - utf16_to_utf8(t, []u16{'t', 'e', 's', 't'}, "test", true); - utf16_to_utf8(t, []u16{'t', 'e', 's', 't', 0}, "test", true); - utf16_to_utf8(t, []u16{'t', 'e', 0, 's', 't'}, "te", true); - utf16_to_utf8(t, []u16{'t', 'e', 0, 's', 't', 0}, "te", true); + utf16_to_utf8(t, []u16{}, "", true) + utf16_to_utf8(t, []u16{0}, "", true) + utf16_to_utf8(t, []u16{0, 't', 'e', 's', 't'}, "", true) + utf16_to_utf8(t, []u16{0, 't', 'e', 's', 't', 0}, "", true) + utf16_to_utf8(t, []u16{'t', 'e', 's', 't'}, "test", true) + utf16_to_utf8(t, []u16{'t', 'e', 's', 't', 0}, "test", true) + utf16_to_utf8(t, []u16{'t', 'e', 0, 's', 't'}, "te", true) + utf16_to_utf8(t, []u16{'t', 'e', 0, 's', 't', 0}, "te", true) - wstring_to_utf8(t, []u16{}, "", true); - wstring_to_utf8(t, []u16{0}, "", true); - wstring_to_utf8(t, []u16{0, 't', 'e', 's', 't'}, "", true); - wstring_to_utf8(t, []u16{0, 't', 'e', 's', 't', 0}, "", true); - wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 0}, "test", true); - wstring_to_utf8(t, []u16{'t', 'e', 0, 's', 't'}, "te", true); - wstring_to_utf8(t, []u16{'t', 'e', 0, 's', 't', 0}, "te", true); + wstring_to_utf8(t, []u16{}, "", true) + wstring_to_utf8(t, []u16{0}, "", true) + wstring_to_utf8(t, []u16{0, 't', 'e', 's', 't'}, "", true) + wstring_to_utf8(t, []u16{0, 't', 'e', 's', 't', 0}, "", true) + wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 0}, "test", true) + wstring_to_utf8(t, []u16{'t', 'e', 0, 's', 't'}, "te", true) + wstring_to_utf8(t, []u16{'t', 'e', 0, 's', 't', 0}, "te", true) // WARNING: Passing a non-zero-terminated string to wstring_to_utf8 is dangerous, // as it will go out of bounds looking for a zero. // It will "fail" or "succeed" by having a zero just after the end of the input string or not. - wstring_to_utf8(t, []u16{'t', 'e', 's', 't'}, "test", false); - wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 0}[:4], "test", true); - wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 'q'}[:4], "test", false); + wstring_to_utf8(t, []u16{'t', 'e', 's', 't'}, "test", false) + wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 0}[:4], "test", true) + wstring_to_utf8(t, []u16{'t', 'e', 's', 't', 'q'}[:4], "test", false) } \ No newline at end of file diff --git a/core/sys/windows/kernel32.odin b/core/sys/windows/kernel32.odin index 1f8927a16..ac959db2d 100644 --- a/core/sys/windows/kernel32.odin +++ b/core/sys/windows/kernel32.odin @@ -272,6 +272,11 @@ foreign kernel32 { HeapReAlloc :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID --- HeapFree :: proc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL --- + LocalAlloc :: proc(flags: UINT, bytes: SIZE_T) -> LPVOID --- + LocalReAlloc :: proc(mem: LPVOID, bytes: SIZE_T, flags: UINT) -> LPVOID --- + LocalFree :: proc(mem: LPVOID) -> LPVOID --- + + ReadDirectoryChangesW :: proc( hDirectory: HANDLE, lpBuffer: LPVOID, diff --git a/core/sys/windows/util.odin b/core/sys/windows/util.odin index f448f6bc5..5c8f35bef 100644 --- a/core/sys/windows/util.odin +++ b/core/sys/windows/util.odin @@ -2,7 +2,7 @@ package sys_windows import "core:strings" -import "core:sys/win32" +import "core:runtime" import "core:intrinsics" L :: intrinsics.constant_utf16_cstring @@ -56,16 +56,16 @@ utf8_to_wstring :: proc(s: string, allocator := context.temp_allocator) -> wstri return nil } -wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string) { +wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { context.allocator = allocator if N <= 0 { - return "" + return } n := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), nil, 0, nil, nil) if n == 0 { - return "" + return } // If N == -1 the call to WideCharToMultiByte assume the wide string is null terminated @@ -73,12 +73,12 @@ wstring_to_utf8 :: proc(s: wstring, N: int, allocator := context.temp_allocator) // also null terminated. // If N != -1 it assumes the wide string is not null terminated and the resulting string // will not be null terminated, we therefore have to force it to be null terminated manually. - text := make([]byte, n+1 if N != -1 else n) + text := make([]byte, n+1 if N != -1 else n) or_return n1 := WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, s, i32(N), raw_data(text), n, nil, nil) if n1 == 0 { delete(text, allocator) - return "" + return } for i in 0.. string { +utf16_to_utf8 :: proc(s: []u16, allocator := context.temp_allocator) -> (res: string, err: runtime.Allocator_Error) { if len(s) == 0 { - return "" + return "", nil } return wstring_to_utf8(raw_data(s), len(s), allocator) } @@ -216,7 +216,7 @@ get_computer_name_and_account_sid :: proc(username: string) -> (computer_name: s if !res { return "", {}, false } - computer_name = utf16_to_utf8(cname_w, context.temp_allocator) + computer_name = utf16_to_utf8(cname_w, context.temp_allocator) or_else "" ok = true return @@ -306,7 +306,7 @@ add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) { if res == false { return false, "" } - defer win32.local_free(sb) + defer LocalFree(sb) pszProfilePath := make([]u16, 257, context.temp_allocator) res2 := CreateProfile( @@ -318,7 +318,7 @@ add_user_profile :: proc(username: string) -> (ok: bool, profile_path: string) { if res2 != 0 { return false, "" } - profile_path = wstring_to_utf8(&pszProfilePath[0], 257) + profile_path = wstring_to_utf8(&pszProfilePath[0], 257) or_else "" return true, profile_path } @@ -336,7 +336,7 @@ delete_user_profile :: proc(username: string) -> (ok: bool) { if res == false { return false } - defer win32.local_free(sb) + defer LocalFree(sb) res2 := DeleteProfileW( sb,