diff --git a/std/cstr.zig b/std/cstr.zig index 7e61381b9..e29f90fc0 100644 --- a/std/cstr.zig +++ b/std/cstr.zig @@ -45,5 +45,5 @@ pub fn addNullByte(allocator: &mem.Allocator, slice: []const u8) -> %[]u8 { const result = %return allocator.alloc(u8, slice.len + 1); mem.copy(u8, result, slice); result[slice.len] = 0; - return result[0..slice.len]; + return result; } diff --git a/std/os/index.zig b/std/os/index.zig index a9d91972b..0b536d319 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -322,7 +322,7 @@ pub fn createNullDelimitedEnvMap(allocator: &Allocator, env_map: &const BufMap) pub fn freeNullDelimitedEnvMap(allocator: &Allocator, envp_buf: []?&u8) { for (envp_buf) |env| { - const env_buf = if (env) |ptr| cstr.toSlice(ptr) else break; + const env_buf = if (env) |ptr| ptr[0 .. cstr.len(ptr) + 1] else break; allocator.free(env_buf); } allocator.free(envp_buf); @@ -490,6 +490,28 @@ test "os.getCwd" { } pub fn symLink(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { + if (is_windows) { + return symLinkWindows(allocator, existing_path, new_path); + } else { + return symLinkPosix(allocator, existing_path, new_path); + } +} + +pub fn symLinkWindows(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { + const existing_with_null = %return cstr.addNullByte(allocator, existing_path); + defer allocator.free(existing_with_null); + const new_with_null = %return cstr.addNullByte(allocator, new_path); + defer allocator.free(new_with_null); + + if (windows.CreateSymbolicLinkA(existing_with_null.ptr, new_with_null.ptr, 0) == 0) { + const err = windows.GetLastError(); + return switch (err) { + else => error.Unexpected, + }; + } +} + +pub fn symLinkPosix(allocator: &Allocator, existing_path: []const u8, new_path: []const u8) -> %void { const full_buf = %return allocator.alloc(u8, existing_path.len + new_path.len + 2); defer allocator.free(full_buf); diff --git a/std/os/windows/index.zig b/std/os/windows/index.zig index 424b3eba4..eb066c7aa 100644 --- a/std/os/windows/index.zig +++ b/std/os/windows/index.zig @@ -25,6 +25,9 @@ pub extern "kernel32" stdcallcc fn CreateProcessA(lpApplicationName: ?LPCSTR, lp dwCreationFlags: DWORD, lpEnvironment: ?LPVOID, lpCurrentDirectory: ?LPCSTR, lpStartupInfo: &STARTUPINFOA, lpProcessInformation: &PROCESS_INFORMATION) -> BOOL; +pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(lpSymlinkFileName: LPCSTR, lpTargetFileName: LPCSTR, + dwFlags: DWORD) -> BOOLEAN; + pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) -> bool; pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) -> noreturn; @@ -74,34 +77,34 @@ pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lp pub const PROV_RSA_FULL = 1; -pub const UNICODE = false; -pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR; -pub const LPWSTR = &WCHAR; -pub const LPSTR = &CHAR; -pub const CHAR = u8; -pub const PWSTR = &WCHAR; -pub const SIZE_T = usize; - pub const BOOL = bool; +pub const BOOLEAN = BYTE; pub const BYTE = u8; -pub const WORD = u16; +pub const CHAR = u8; pub const DWORD = u32; pub const FLOAT = f32; pub const HANDLE = &c_void; -pub const HINSTANCE = &@OpaqueType(); pub const HCRYPTPROV = ULONG_PTR; -pub const LPCTSTR = &const TCHAR; +pub const HINSTANCE = &@OpaqueType(); +pub const INT = c_int; +pub const LPBYTE = &BYTE; pub const LPCSTR = &const CHAR; +pub const LPCTSTR = &const TCHAR; +pub const LPCVOID = &const c_void; pub const LPDWORD = &DWORD; +pub const LPSTR = &CHAR; +pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR; pub const LPVOID = &c_void; +pub const LPWSTR = &WCHAR; pub const PVOID = &c_void; +pub const PWSTR = &WCHAR; +pub const SIZE_T = usize; pub const TCHAR = if (UNICODE) WCHAR else u8; pub const UINT = c_uint; -pub const INT = c_int; pub const ULONG_PTR = usize; +pub const UNICODE = false; pub const WCHAR = u16; -pub const LPCVOID = &const c_void; -pub const LPBYTE = &BYTE; +pub const WORD = u16; /// The standard input device. Initially, this is the console input buffer, CONIN$. pub const STD_INPUT_HANDLE = @maxValue(DWORD) - 10 + 1;