LCOV - code coverage report
Current view: top level - src - os.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 271 559 48.5 %
Date: 1970-01-01 00:00:01 Functions: 34 45 75.6 %
Branches: 102 285 35.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2015 Andrew Kelley
       3                 :            :  *
       4                 :            :  * This file is part of zig, which is MIT licensed.
       5                 :            :  * See http://opensource.org/licenses/MIT
       6                 :            :  */
       7                 :            : 
       8                 :            : #include "os.hpp"
       9                 :            : #include "util.hpp"
      10                 :            : #include "error.hpp"
      11                 :            : 
      12                 :            : #if defined(_WIN32)
      13                 :            : 
      14                 :            : #if !defined(NOMINMAX)
      15                 :            : #define NOMINMAX
      16                 :            : #endif
      17                 :            : 
      18                 :            : #if !defined(VC_EXTRALEAN)
      19                 :            : #define VC_EXTRALEAN
      20                 :            : #endif
      21                 :            : 
      22                 :            : #if !defined(WIN32_LEAN_AND_MEAN)
      23                 :            : #define WIN32_LEAN_AND_MEAN
      24                 :            : #endif
      25                 :            : 
      26                 :            : #if !defined(_WIN32_WINNT)
      27                 :            : #define _WIN32_WINNT 0x600
      28                 :            : #endif
      29                 :            : 
      30                 :            : #if !defined(NTDDI_VERSION)
      31                 :            : #define NTDDI_VERSION 0x06000000
      32                 :            : #endif
      33                 :            : 
      34                 :            : #include <windows.h>
      35                 :            : #include <shlobj.h>
      36                 :            : #include <io.h>
      37                 :            : #include <fcntl.h>
      38                 :            : #include <ntsecapi.h>
      39                 :            : 
      40                 :            : typedef SSIZE_T ssize_t;
      41                 :            : #else
      42                 :            : #define ZIG_OS_POSIX
      43                 :            : 
      44                 :            : #include <unistd.h>
      45                 :            : #include <sys/types.h>
      46                 :            : #include <sys/stat.h>
      47                 :            : #include <sys/wait.h>
      48                 :            : #include <sys/resource.h>
      49                 :            : #include <fcntl.h>
      50                 :            : #include <limits.h>
      51                 :            : #include <spawn.h>
      52                 :            : 
      53                 :            : #endif
      54                 :            : 
      55                 :            : #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
      56                 :            : #include <link.h>
      57                 :            : #endif
      58                 :            : 
      59                 :            : #if defined(ZIG_OS_LINUX)
      60                 :            : #include <sys/auxv.h>
      61                 :            : #endif
      62                 :            : 
      63                 :            : #if defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
      64                 :            : #include <sys/sysctl.h>
      65                 :            : #endif
      66                 :            : 
      67                 :            : #if defined(__MACH__)
      68                 :            : #include <mach/clock.h>
      69                 :            : #include <mach/mach.h>
      70                 :            : #include <mach-o/dyld.h>
      71                 :            : #endif
      72                 :            : 
      73                 :            : #if defined(ZIG_OS_WINDOWS)
      74                 :            : static uint64_t windows_perf_freq;
      75                 :            : #elif defined(__MACH__)
      76                 :            : static clock_serv_t macos_calendar_clock;
      77                 :            : static clock_serv_t macos_monotonic_clock;
      78                 :            : #endif
      79                 :            : 
      80                 :            : #include <stdlib.h>
      81                 :            : #include <errno.h>
      82                 :            : #include <time.h>
      83                 :            : 
      84                 :            : // Apple doesn't provide the environ global variable
      85                 :            : #if defined(__APPLE__) && !defined(environ)
      86                 :            : #include <crt_externs.h>
      87                 :            : #define environ (*_NSGetEnviron())
      88                 :            : #elif defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
      89                 :            : extern char **environ;
      90                 :            : #endif
      91                 :            : 
      92                 :            : #if defined(ZIG_OS_POSIX)
      93                 :         45 : static void populate_termination(Termination *term, int status) {
      94         [ +  - ]:         45 :     if (WIFEXITED(status)) {
      95                 :         45 :         term->how = TerminationIdClean;
      96                 :         45 :         term->code = WEXITSTATUS(status);
      97         [ #  # ]:          0 :     } else if (WIFSIGNALED(status)) {
      98                 :          0 :         term->how = TerminationIdSignaled;
      99                 :          0 :         term->code = WTERMSIG(status);
     100         [ #  # ]:          0 :     } else if (WIFSTOPPED(status)) {
     101                 :          0 :         term->how = TerminationIdStopped;
     102                 :          0 :         term->code = WSTOPSIG(status);
     103                 :            :     } else {
     104                 :          0 :         term->how = TerminationIdUnknown;
     105                 :          0 :         term->code = status;
     106                 :            :     }
     107                 :         45 : }
     108                 :            : 
     109                 :         45 : static void os_spawn_process_posix(ZigList<const char *> &args, Termination *term) {
     110                 :         45 :     const char **argv = allocate<const char *>(args.length + 1);
     111         [ +  + ]:       2178 :     for (size_t i = 0; i < args.length; i += 1) {
     112                 :       2133 :         argv[i] = args.at(i);
     113                 :            :     }
     114                 :         45 :     argv[args.length] = nullptr;
     115                 :            : 
     116                 :            :     pid_t pid;
     117                 :         45 :     int rc = posix_spawnp(&pid, args.at(0), nullptr, nullptr, const_cast<char *const*>(argv), environ);
     118         [ -  + ]:         45 :     if (rc != 0) {
     119                 :          0 :         zig_panic("posix_spawn failed: %s", strerror(rc));
     120                 :            :     }
     121                 :            : 
     122                 :            :     int status;
     123                 :         45 :     waitpid(pid, &status, 0);
     124                 :         45 :     populate_termination(term, status);
     125                 :         45 : }
     126                 :            : #endif
     127                 :            : 
     128                 :            : #if defined(ZIG_OS_WINDOWS)
     129                 :            : 
     130                 :            : static void os_windows_create_command_line(Buf *command_line, ZigList<const char *> &args) {
     131                 :            :     buf_resize(command_line, 0);
     132                 :            :     const char *prefix = "\"";
     133                 :            :     for (size_t arg_i = 0; arg_i < args.length; arg_i += 1) {
     134                 :            :         const char *arg = args.at(arg_i);
     135                 :            :         buf_append_str(command_line, prefix);
     136                 :            :         prefix = " \"";
     137                 :            :         size_t arg_len = strlen(arg);
     138                 :            :         for (size_t c_i = 0; c_i < arg_len; c_i += 1) {
     139                 :            :             if (arg[c_i] == '\"') {
     140                 :            :                 zig_panic("TODO");
     141                 :            :             }
     142                 :            :             buf_append_char(command_line, arg[c_i]);
     143                 :            :         }
     144                 :            :         buf_append_char(command_line, '\"');
     145                 :            :     }
     146                 :            : }
     147                 :            : 
     148                 :            : static void os_spawn_process_windows(ZigList<const char *> &args, Termination *term) {
     149                 :            :     Buf command_line = BUF_INIT;
     150                 :            :     os_windows_create_command_line(&command_line, args);
     151                 :            : 
     152                 :            :     PROCESS_INFORMATION piProcInfo = {0};
     153                 :            :     STARTUPINFO siStartInfo = {0};
     154                 :            :     siStartInfo.cb = sizeof(STARTUPINFO);
     155                 :            : 
     156                 :            :     const char *exe = args.at(0);
     157                 :            :     BOOL success = CreateProcessA(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
     158                 :            :             &siStartInfo, &piProcInfo);
     159                 :            : 
     160                 :            :     if (!success) {
     161                 :            :         zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line));
     162                 :            :     }
     163                 :            : 
     164                 :            :     WaitForSingleObject(piProcInfo.hProcess, INFINITE);
     165                 :            : 
     166                 :            :     DWORD exit_code;
     167                 :            :     if (!GetExitCodeProcess(piProcInfo.hProcess, &exit_code)) {
     168                 :            :         zig_panic("GetExitCodeProcess failed");
     169                 :            :     }
     170                 :            :     term->how = TerminationIdClean;
     171                 :            :     term->code = exit_code;
     172                 :            : }
     173                 :            : #endif
     174                 :            : 
     175                 :         45 : void os_spawn_process(ZigList<const char *> &args, Termination *term) {
     176                 :            : #if defined(ZIG_OS_WINDOWS)
     177                 :            :     os_spawn_process_windows(args, term);
     178                 :            : #elif defined(ZIG_OS_POSIX)
     179                 :         45 :     os_spawn_process_posix(args, term);
     180                 :            : #else
     181                 :            : #error "missing os_spawn_process implementation"
     182                 :            : #endif
     183                 :         45 : }
     184                 :            : 
     185                 :       2416 : void os_path_dirname(Buf *full_path, Buf *out_dirname) {
     186                 :       2416 :     return os_path_split(full_path, out_dirname, nullptr);
     187                 :            : }
     188                 :            : 
     189                 :      62498 : bool os_is_sep(uint8_t c) {
     190                 :            : #if defined(ZIG_OS_WINDOWS)
     191                 :            :     return c == '\\' || c == '/';
     192                 :            : #else
     193                 :      62498 :     return c == '/';
     194                 :            : #endif
     195                 :            : }
     196                 :            : 
     197                 :       4313 : void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
     198                 :       4313 :     size_t len = buf_len(full_path);
     199         [ +  - ]:       4313 :     if (len != 0) {
     200                 :       4313 :         size_t last_index = len - 1;
     201                 :       4313 :         char last_char = buf_ptr(full_path)[last_index];
     202         [ -  + ]:       4313 :         if (os_is_sep(last_char)) {
     203         [ #  # ]:          0 :             if (last_index == 0) {
     204         [ #  # ]:          0 :                 if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1);
     205         [ #  # ]:          0 :                 if (out_basename) buf_init_from_str(out_basename, "");
     206                 :       4313 :                 return;
     207                 :            :             }
     208                 :          0 :             last_index -= 1;
     209                 :            :         }
     210                 :       4313 :         for (size_t i = last_index;;) {
     211                 :      51503 :             uint8_t c = buf_ptr(full_path)[i];
     212         [ +  + ]:      51503 :             if (os_is_sep(c)) {
     213         [ +  + ]:       4313 :                 if (out_dirname) {
     214         [ +  - ]:       4259 :                     buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i);
     215                 :            :                 }
     216         [ +  + ]:       4313 :                 if (out_basename) {
     217                 :       1897 :                     buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));
     218                 :            :                 }
     219                 :       4313 :                 return;
     220                 :            :             }
     221         [ -  + ]:      47190 :             if (i == 0) break;
     222                 :      47190 :             i -= 1;
     223                 :      47190 :         }
     224                 :            :     }
     225         [ #  # ]:          0 :     if (out_dirname) buf_init_from_mem(out_dirname, ".", 1);
     226         [ #  # ]:          0 :     if (out_basename) buf_init_from_buf(out_basename, full_path);
     227                 :            : }
     228                 :            : 
     229                 :       3662 : void os_path_extname(Buf *full_path, Buf *out_basename, Buf *out_extname) {
     230         [ -  + ]:       3662 :     if (buf_len(full_path) == 0) {
     231         [ #  # ]:          0 :         if (out_basename) buf_init_from_str(out_basename, "");
     232         [ #  # ]:          0 :         if (out_extname) buf_init_from_str(out_extname, "");
     233                 :          0 :         return;
     234                 :            :     }
     235                 :       3662 :     size_t i = buf_len(full_path) - 1;
     236                 :            :     while (true) {
     237         [ +  + ]:      14552 :         if (buf_ptr(full_path)[i] == '.') {
     238         [ +  - ]:       3662 :             if (out_basename) {
     239                 :       3662 :                 buf_resize(out_basename, 0);
     240                 :       3662 :                 buf_append_mem(out_basename, buf_ptr(full_path), i);
     241                 :            :             }
     242                 :            : 
     243         [ -  + ]:       3662 :             if (out_extname) {
     244                 :          0 :                 buf_resize(out_extname, 0);
     245                 :          0 :                 buf_append_mem(out_extname, buf_ptr(full_path) + i, buf_len(full_path) - i);
     246                 :            :             }
     247                 :       3662 :             return;
     248                 :            :         }
     249                 :            : 
     250         [ -  + ]:      10890 :         if (i == 0) {
     251         [ #  # ]:          0 :             if (out_basename) buf_init_from_buf(out_basename, full_path);
     252         [ #  # ]:          0 :             if (out_extname) buf_init_from_str(out_extname, "");
     253                 :          0 :             return;
     254                 :            :         }
     255                 :      10890 :         i -= 1;
     256                 :            :     }
     257                 :            : }
     258                 :            : 
     259                 :       6271 : void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
     260         [ -  + ]:       6271 :     if (buf_len(dirname) == 0) {
     261                 :          0 :         buf_init_from_buf(out_full_path, basename);
     262                 :          0 :         return;
     263                 :            :     }
     264                 :            : 
     265                 :       6271 :     buf_init_from_buf(out_full_path, dirname);
     266                 :       6271 :     uint8_t c = *(buf_ptr(out_full_path) + buf_len(out_full_path) - 1);
     267         [ +  - ]:       6271 :     if (!os_is_sep(c))
     268                 :       6271 :         buf_append_char(out_full_path, ZIG_OS_SEP_CHAR);
     269                 :       6271 :     buf_append_buf(out_full_path, basename);
     270                 :            : }
     271                 :            : 
     272                 :          0 : Error os_path_real(Buf *rel_path, Buf *out_abs_path) {
     273                 :            : #if defined(ZIG_OS_WINDOWS)
     274                 :            :     buf_resize(out_abs_path, 4096);
     275                 :            :     if (_fullpath(buf_ptr(out_abs_path), buf_ptr(rel_path), buf_len(out_abs_path)) == nullptr) {
     276                 :            :         zig_panic("_fullpath failed");
     277                 :            :     }
     278                 :            :     buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path)));
     279                 :            :     return ErrorNone;
     280                 :            : #elif defined(ZIG_OS_POSIX)
     281                 :          0 :     buf_resize(out_abs_path, PATH_MAX + 1);
     282                 :          0 :     char *result = realpath(buf_ptr(rel_path), buf_ptr(out_abs_path));
     283         [ #  # ]:          0 :     if (!result) {
     284                 :          0 :         int err = errno;
     285         [ #  # ]:          0 :         if (err == EACCES) {
     286                 :          0 :             return ErrorAccess;
     287         [ #  # ]:          0 :         } else if (err == ENOENT) {
     288                 :          0 :             return ErrorFileNotFound;
     289         [ #  # ]:          0 :         } else if (err == ENOMEM) {
     290                 :          0 :             return ErrorNoMem;
     291                 :            :         } else {
     292                 :          0 :             return ErrorFileSystem;
     293                 :            :         }
     294                 :            :     }
     295                 :          0 :     buf_resize(out_abs_path, strlen(buf_ptr(out_abs_path)));
     296                 :          0 :     return ErrorNone;
     297                 :            : #else
     298                 :            : #error "missing os_path_real implementation"
     299                 :            : #endif
     300                 :            : }
     301                 :            : 
     302                 :            : #if defined(ZIG_OS_WINDOWS)
     303                 :            : // Ported from std/os/path.zig
     304                 :            : static bool isAbsoluteWindows(Slice<uint8_t> path) {
     305                 :            :     if (path.ptr[0] == '/')
     306                 :            :         return true;
     307                 :            : 
     308                 :            :     if (path.ptr[0] == '\\') {
     309                 :            :         return true;
     310                 :            :     }
     311                 :            :     if (path.len < 3) {
     312                 :            :         return false;
     313                 :            :     }
     314                 :            :     if (path.ptr[1] == ':') {
     315                 :            :         if (path.ptr[2] == '/')
     316                 :            :             return true;
     317                 :            :         if (path.ptr[2] == '\\')
     318                 :            :             return true;
     319                 :            :     }
     320                 :            :     return false;
     321                 :            : }
     322                 :            : #endif
     323                 :            : 
     324                 :       9177 : bool os_path_is_absolute(Buf *path) {
     325                 :            : #if defined(ZIG_OS_WINDOWS)
     326                 :            :     return isAbsoluteWindows(buf_to_slice(path));
     327                 :            : #elif defined(ZIG_OS_POSIX)
     328                 :       9177 :     return buf_ptr(path)[0] == '/';
     329                 :            : #else
     330                 :            : #error "missing os_path_is_absolute implementation"
     331                 :            : #endif
     332                 :            : }
     333                 :            : 
     334                 :            : #if defined(ZIG_OS_WINDOWS)
     335                 :            : 
     336                 :            : enum WindowsPathKind {
     337                 :            :     WindowsPathKindNone,
     338                 :            :     WindowsPathKindDrive,
     339                 :            :     WindowsPathKindNetworkShare,
     340                 :            : };
     341                 :            : 
     342                 :            : struct WindowsPath {
     343                 :            :     Slice<uint8_t> disk_designator;
     344                 :            :     WindowsPathKind kind;
     345                 :            :     bool is_abs;
     346                 :            : };
     347                 :            : 
     348                 :            : 
     349                 :            : // Ported from std/os/path.zig
     350                 :            : static WindowsPath windowsParsePath(Slice<uint8_t> path) {
     351                 :            :     if (path.len >= 2 && path.ptr[1] == ':') {
     352                 :            :         return WindowsPath{
     353                 :            :             path.slice(0, 2),
     354                 :            :             WindowsPathKindDrive,
     355                 :            :             isAbsoluteWindows(path),
     356                 :            :         };
     357                 :            :     }
     358                 :            :     if (path.len >= 1 && (path.ptr[0] == '/' || path.ptr[0] == '\\') &&
     359                 :            :         (path.len == 1 || (path.ptr[1] != '/' && path.ptr[1] != '\\')))
     360                 :            :     {
     361                 :            :         return WindowsPath{
     362                 :            :             path.slice(0, 0),
     363                 :            :             WindowsPathKindNone,
     364                 :            :             true,
     365                 :            :         };
     366                 :            :     }
     367                 :            :     WindowsPath relative_path = {
     368                 :            :         str(""),
     369                 :            :         WindowsPathKindNone,
     370                 :            :         false,
     371                 :            :     };
     372                 :            :     if (path.len < strlen("//a/b")) {
     373                 :            :         return relative_path;
     374                 :            :     }
     375                 :            : 
     376                 :            :     {
     377                 :            :         if (memStartsWith(path, str("//"))) {
     378                 :            :             if (path.ptr[2] == '/') {
     379                 :            :                 return relative_path;
     380                 :            :             }
     381                 :            : 
     382                 :            :             SplitIterator it = memSplit(path, str("/"));
     383                 :            :             {
     384                 :            :                 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     385                 :            :                 if (!opt_component.is_some) return relative_path;
     386                 :            :             }
     387                 :            :             {
     388                 :            :                 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     389                 :            :                 if (!opt_component.is_some) return relative_path;
     390                 :            :             }
     391                 :            :             return WindowsPath{
     392                 :            :                 path.slice(0, it.index),
     393                 :            :                 WindowsPathKindNetworkShare,
     394                 :            :                 isAbsoluteWindows(path),
     395                 :            :             };
     396                 :            :         }
     397                 :            :     }
     398                 :            :     {
     399                 :            :         if (memStartsWith(path, str("\\\\"))) {
     400                 :            :             if (path.ptr[2] == '\\') {
     401                 :            :                 return relative_path;
     402                 :            :             }
     403                 :            : 
     404                 :            :             SplitIterator it = memSplit(path, str("\\"));
     405                 :            :             {
     406                 :            :                 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     407                 :            :                 if (!opt_component.is_some) return relative_path;
     408                 :            :             }
     409                 :            :             {
     410                 :            :                 Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     411                 :            :                 if (!opt_component.is_some) return relative_path;
     412                 :            :             }
     413                 :            :             return WindowsPath{
     414                 :            :                 path.slice(0, it.index),
     415                 :            :                 WindowsPathKindNetworkShare,
     416                 :            :                 isAbsoluteWindows(path),
     417                 :            :             };
     418                 :            :         }
     419                 :            :     }
     420                 :            :     return relative_path;
     421                 :            : }
     422                 :            : 
     423                 :            : // Ported from std/os/path.zig
     424                 :            : static uint8_t asciiUpper(uint8_t byte) {
     425                 :            :     if (byte >= 'a' && byte <= 'z') {
     426                 :            :         return 'A' + (byte - 'a');
     427                 :            :     }
     428                 :            :     return byte;
     429                 :            : }
     430                 :            : 
     431                 :            : // Ported from std/os/path.zig
     432                 :            : static bool asciiEqlIgnoreCase(Slice<uint8_t> s1, Slice<uint8_t> s2) {
     433                 :            :     if (s1.len != s2.len)
     434                 :            :         return false;
     435                 :            :     for (size_t i = 0; i < s1.len; i += 1) {
     436                 :            :         if (asciiUpper(s1.ptr[i]) != asciiUpper(s2.ptr[i]))
     437                 :            :             return false;
     438                 :            :     }
     439                 :            :     return true;
     440                 :            : }
     441                 :            : 
     442                 :            : // Ported from std/os/path.zig
     443                 :            : static bool compareDiskDesignators(WindowsPathKind kind, Slice<uint8_t> p1, Slice<uint8_t> p2) {
     444                 :            :     switch (kind) {
     445                 :            :         case WindowsPathKindNone:
     446                 :            :             assert(p1.len == 0);
     447                 :            :             assert(p2.len == 0);
     448                 :            :             return true;
     449                 :            :         case WindowsPathKindDrive:
     450                 :            :             return asciiUpper(p1.ptr[0]) == asciiUpper(p2.ptr[0]);
     451                 :            :         case WindowsPathKindNetworkShare:
     452                 :            :             uint8_t sep1 = p1.ptr[0];
     453                 :            :             uint8_t sep2 = p2.ptr[0];
     454                 :            : 
     455                 :            :             SplitIterator it1 = memSplit(p1, {&sep1, 1});
     456                 :            :             SplitIterator it2 = memSplit(p2, {&sep2, 1});
     457                 :            : 
     458                 :            :             // TODO ASCII is wrong, we actually need full unicode support to compare paths.
     459                 :            :             return asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value) &&
     460                 :            :                 asciiEqlIgnoreCase(SplitIterator_next(&it1).value, SplitIterator_next(&it2).value);
     461                 :            :     }
     462                 :            :     zig_unreachable();
     463                 :            : }
     464                 :            : 
     465                 :            : // Ported from std/os/path.zig
     466                 :            : static Buf os_path_resolve_windows(Buf **paths_ptr, size_t paths_len) {
     467                 :            :     if (paths_len == 0) {
     468                 :            :         Buf cwd = BUF_INIT;
     469                 :            :         int err;
     470                 :            :         if ((err = os_get_cwd(&cwd))) {
     471                 :            :             zig_panic("get cwd failed");
     472                 :            :         }
     473                 :            :         return cwd;
     474                 :            :     }
     475                 :            : 
     476                 :            :     // determine which disk designator we will result with, if any
     477                 :            :     char result_drive_buf[3] = {'_', ':', '\0'}; // 0 needed for strlen later
     478                 :            :     Slice<uint8_t> result_disk_designator = str("");
     479                 :            :     WindowsPathKind have_drive_kind = WindowsPathKindNone;
     480                 :            :     bool have_abs_path = false;
     481                 :            :     size_t first_index = 0;
     482                 :            :     size_t max_size = 0;
     483                 :            :     for (size_t i = 0; i < paths_len; i += 1) {
     484                 :            :         Slice<uint8_t> p = buf_to_slice(paths_ptr[i]);
     485                 :            :         WindowsPath parsed = windowsParsePath(p);
     486                 :            :         if (parsed.is_abs) {
     487                 :            :             have_abs_path = true;
     488                 :            :             first_index = i;
     489                 :            :             max_size = result_disk_designator.len;
     490                 :            :         }
     491                 :            :         switch (parsed.kind) {
     492                 :            :             case WindowsPathKindDrive:
     493                 :            :                 result_drive_buf[0] = asciiUpper(parsed.disk_designator.ptr[0]);
     494                 :            :                 result_disk_designator = str(result_drive_buf);
     495                 :            :                 have_drive_kind = WindowsPathKindDrive;
     496                 :            :                 break;
     497                 :            :             case WindowsPathKindNetworkShare:
     498                 :            :                 result_disk_designator = parsed.disk_designator;
     499                 :            :                 have_drive_kind = WindowsPathKindNetworkShare;
     500                 :            :                 break;
     501                 :            :             case WindowsPathKindNone:
     502                 :            :                 break;
     503                 :            :         }
     504                 :            :         max_size += p.len + 1;
     505                 :            :     }
     506                 :            : 
     507                 :            :     // if we will result with a disk designator, loop again to determine
     508                 :            :     // which is the last time the disk designator is absolutely specified, if any
     509                 :            :     // and count up the max bytes for paths related to this disk designator
     510                 :            :     if (have_drive_kind != WindowsPathKindNone) {
     511                 :            :         have_abs_path = false;
     512                 :            :         first_index = 0;
     513                 :            :         max_size = result_disk_designator.len;
     514                 :            :         bool correct_disk_designator = false;
     515                 :            : 
     516                 :            :         for (size_t i = 0; i < paths_len; i += 1) {
     517                 :            :             Slice<uint8_t> p = buf_to_slice(paths_ptr[i]);
     518                 :            :             WindowsPath parsed = windowsParsePath(p);
     519                 :            :             if (parsed.kind != WindowsPathKindNone) {
     520                 :            :                 if (parsed.kind == have_drive_kind) {
     521                 :            :                     correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
     522                 :            :                 } else {
     523                 :            :                     continue;
     524                 :            :                 }
     525                 :            :             }
     526                 :            :             if (!correct_disk_designator) {
     527                 :            :                 continue;
     528                 :            :             }
     529                 :            :             if (parsed.is_abs) {
     530                 :            :                 first_index = i;
     531                 :            :                 max_size = result_disk_designator.len;
     532                 :            :                 have_abs_path = true;
     533                 :            :             }
     534                 :            :             max_size += p.len + 1;
     535                 :            :         }
     536                 :            :     }
     537                 :            : 
     538                 :            :     // Allocate result and fill in the disk designator, calling getCwd if we have to.
     539                 :            :     Slice<uint8_t> result;
     540                 :            :     size_t result_index = 0;
     541                 :            : 
     542                 :            :     if (have_abs_path) {
     543                 :            :         switch (have_drive_kind) {
     544                 :            :             case WindowsPathKindDrive: {
     545                 :            :                 result = Slice<uint8_t>::alloc(max_size);
     546                 :            : 
     547                 :            :                 memCopy(result, result_disk_designator);
     548                 :            :                 result_index += result_disk_designator.len;
     549                 :            :                 break;
     550                 :            :             }
     551                 :            :             case WindowsPathKindNetworkShare: {
     552                 :            :                 result = Slice<uint8_t>::alloc(max_size);
     553                 :            :                 SplitIterator it = memSplit(buf_to_slice(paths_ptr[first_index]), str("/\\"));
     554                 :            :                 Slice<uint8_t> server_name = SplitIterator_next(&it).value;
     555                 :            :                 Slice<uint8_t> other_name = SplitIterator_next(&it).value;
     556                 :            : 
     557                 :            :                 result.ptr[result_index] = '\\';
     558                 :            :                 result_index += 1;
     559                 :            :                 result.ptr[result_index] = '\\';
     560                 :            :                 result_index += 1;
     561                 :            :                 memCopy(result.sliceFrom(result_index), server_name);
     562                 :            :                 result_index += server_name.len;
     563                 :            :                 result.ptr[result_index] = '\\';
     564                 :            :                 result_index += 1;
     565                 :            :                 memCopy(result.sliceFrom(result_index), other_name);
     566                 :            :                 result_index += other_name.len;
     567                 :            : 
     568                 :            :                 result_disk_designator = result.slice(0, result_index);
     569                 :            :                 break;
     570                 :            :             }
     571                 :            :             case WindowsPathKindNone: {
     572                 :            :                 Buf cwd = BUF_INIT;
     573                 :            :                 int err;
     574                 :            :                 if ((err = os_get_cwd(&cwd))) {
     575                 :            :                     zig_panic("get cwd failed");
     576                 :            :                 }
     577                 :            :                 WindowsPath parsed_cwd = windowsParsePath(buf_to_slice(&cwd));
     578                 :            :                 result = Slice<uint8_t>::alloc(max_size + parsed_cwd.disk_designator.len + 1);
     579                 :            :                 memCopy(result, parsed_cwd.disk_designator);
     580                 :            :                 result_index += parsed_cwd.disk_designator.len;
     581                 :            :                 result_disk_designator = result.slice(0, parsed_cwd.disk_designator.len);
     582                 :            :                 if (parsed_cwd.kind == WindowsPathKindDrive) {
     583                 :            :                     result.ptr[0] = asciiUpper(result.ptr[0]);
     584                 :            :                 }
     585                 :            :                 have_drive_kind = parsed_cwd.kind;
     586                 :            :                 break;
     587                 :            :             }
     588                 :            :         }
     589                 :            :     } else {
     590                 :            :         // TODO call get cwd for the result_disk_designator instead of the global one
     591                 :            :         Buf cwd = BUF_INIT;
     592                 :            :         int err;
     593                 :            :         if ((err = os_get_cwd(&cwd))) {
     594                 :            :             zig_panic("get cwd failed");
     595                 :            :         }
     596                 :            :         result = Slice<uint8_t>::alloc(max_size + buf_len(&cwd) + 1);
     597                 :            : 
     598                 :            :         memCopy(result, buf_to_slice(&cwd));
     599                 :            :         result_index += buf_len(&cwd);
     600                 :            :         WindowsPath parsed_cwd = windowsParsePath(result.slice(0, result_index));
     601                 :            :         result_disk_designator = parsed_cwd.disk_designator;
     602                 :            :         if (parsed_cwd.kind == WindowsPathKindDrive) {
     603                 :            :             result.ptr[0] = asciiUpper(result.ptr[0]);
     604                 :            :         }
     605                 :            :         have_drive_kind = parsed_cwd.kind;
     606                 :            :     }
     607                 :            : 
     608                 :            :     // Now we know the disk designator to use, if any, and what kind it is. And our result
     609                 :            :     // is big enough to append all the paths to.
     610                 :            :     bool correct_disk_designator = true;
     611                 :            :     for (size_t i = 0; i < paths_len; i += 1) {
     612                 :            :         Slice<uint8_t> p = buf_to_slice(paths_ptr[i]);
     613                 :            :         WindowsPath parsed = windowsParsePath(p);
     614                 :            : 
     615                 :            :         if (parsed.kind != WindowsPathKindNone) {
     616                 :            :             if (parsed.kind == have_drive_kind) {
     617                 :            :                 correct_disk_designator = compareDiskDesignators(have_drive_kind, result_disk_designator, parsed.disk_designator);
     618                 :            :             } else {
     619                 :            :                 continue;
     620                 :            :             }
     621                 :            :         }
     622                 :            :         if (!correct_disk_designator) {
     623                 :            :             continue;
     624                 :            :         }
     625                 :            :         SplitIterator it = memSplit(p.sliceFrom(parsed.disk_designator.len), str("/\\"));
     626                 :            :         while (true) {
     627                 :            :             Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     628                 :            :             if (!opt_component.is_some) break;
     629                 :            :             Slice<uint8_t> component = opt_component.value;
     630                 :            :             if (memEql(component, str("."))) {
     631                 :            :                 continue;
     632                 :            :             } else if (memEql(component, str(".."))) {
     633                 :            :                 while (true) {
     634                 :            :                     if (result_index == 0 || result_index == result_disk_designator.len)
     635                 :            :                         break;
     636                 :            :                     result_index -= 1;
     637                 :            :                     if (result.ptr[result_index] == '\\' || result.ptr[result_index] == '/')
     638                 :            :                         break;
     639                 :            :                 }
     640                 :            :             } else {
     641                 :            :                 result.ptr[result_index] = '\\';
     642                 :            :                 result_index += 1;
     643                 :            :                 memCopy(result.sliceFrom(result_index), component);
     644                 :            :                 result_index += component.len;
     645                 :            :             }
     646                 :            :         }
     647                 :            :     }
     648                 :            : 
     649                 :            :     if (result_index == result_disk_designator.len) {
     650                 :            :         result.ptr[result_index] = '\\';
     651                 :            :         result_index += 1;
     652                 :            :     }
     653                 :            : 
     654                 :            :     Buf return_value = BUF_INIT;
     655                 :            :     buf_init_from_mem(&return_value, (char *)result.ptr, result_index);
     656                 :            :     return return_value;
     657                 :            : }
     658                 :            : #endif
     659                 :            : 
     660                 :            : #if defined(ZIG_OS_POSIX)
     661                 :            : // Ported from std/os/path.zig
     662                 :       9177 : static Buf os_path_resolve_posix(Buf **paths_ptr, size_t paths_len) {
     663         [ -  + ]:       9177 :     if (paths_len == 0) {
     664                 :          0 :         Buf cwd = BUF_INIT;
     665                 :            :         int err;
     666         [ #  # ]:          0 :         if ((err = os_get_cwd(&cwd))) {
     667                 :          0 :             zig_panic("get cwd failed");
     668                 :            :         }
     669                 :          0 :         return cwd;
     670                 :            :     }
     671                 :            : 
     672                 :       9177 :     size_t first_index = 0;
     673                 :       9177 :     bool have_abs = false;
     674                 :       9177 :     size_t max_size = 0;
     675         [ +  + ]:      18354 :     for (size_t i = 0; i < paths_len; i += 1) {
     676                 :       9177 :         Buf *p = paths_ptr[i];
     677         [ +  + ]:       9177 :         if (os_path_is_absolute(p)) {
     678                 :       9175 :             first_index = i;
     679                 :       9175 :             have_abs = true;
     680                 :       9175 :             max_size = 0;
     681                 :            :         }
     682                 :       9177 :         max_size += buf_len(p) + 1;
     683                 :            :     }
     684                 :            : 
     685                 :            :     uint8_t *result_ptr;
     686                 :            :     size_t result_len;
     687                 :       9177 :     size_t result_index = 0;
     688                 :            : 
     689         [ +  + ]:       9177 :     if (have_abs) {
     690                 :       9175 :         result_len = max_size;
     691                 :       9175 :         result_ptr = allocate_nonzero<uint8_t>(result_len);
     692                 :            :     } else {
     693                 :          2 :         Buf cwd = BUF_INIT;
     694                 :            :         int err;
     695         [ -  + ]:          2 :         if ((err = os_get_cwd(&cwd))) {
     696                 :          0 :             zig_panic("get cwd failed");
     697                 :            :         }
     698                 :          2 :         result_len = max_size + buf_len(&cwd) + 1;
     699                 :          2 :         result_ptr = allocate_nonzero<uint8_t>(result_len);
     700                 :          2 :         memcpy(result_ptr, buf_ptr(&cwd), buf_len(&cwd));
     701                 :          2 :         result_index += buf_len(&cwd);
     702                 :            :     }
     703                 :            : 
     704         [ +  + ]:      18354 :     for (size_t i = first_index; i < paths_len; i += 1) {
     705                 :       9177 :         Buf *p = paths_ptr[i];
     706                 :       9177 :         SplitIterator it = memSplit(buf_to_slice(p), str("/"));
     707                 :            :         while (true) {
     708                 :      88685 :             Optional<Slice<uint8_t>> opt_component = SplitIterator_next(&it);
     709         [ +  + ]:      88685 :             if (!opt_component.is_some) break;
     710                 :      79508 :             Slice<uint8_t> component = opt_component.value;
     711                 :            : 
     712         [ +  + ]:      79508 :             if (memEql<uint8_t>(component, str("."))) {
     713                 :          2 :                 continue;
     714         [ +  + ]:      79506 :             } else if (memEql<uint8_t>(component, str(".."))) {
     715                 :            :                 while (true) {
     716         [ -  + ]:       1050 :                     if (result_index == 0)
     717                 :          0 :                         break;
     718                 :        858 :                     result_index -= 1;
     719         [ +  + ]:        858 :                     if (result_ptr[result_index] == '/')
     720                 :        192 :                         break;
     721                 :            :                 }
     722                 :            :             } else {
     723                 :      79314 :                 result_ptr[result_index] = '/';
     724                 :      79314 :                 result_index += 1;
     725                 :      79314 :                 memcpy(result_ptr + result_index, component.ptr, component.len);
     726                 :      79506 :                 result_index += component.len;
     727                 :            :             }
     728                 :      79508 :         }
     729                 :            :     }
     730                 :            : 
     731         [ -  + ]:       9177 :     if (result_index == 0) {
     732                 :          0 :         result_ptr[0] = '/';
     733                 :          0 :         result_index += 1;
     734                 :            :     }
     735                 :            : 
     736                 :       9177 :     Buf return_value = BUF_INIT;
     737                 :       9177 :     buf_init_from_mem(&return_value, (char *)result_ptr, result_index);
     738                 :       9177 :     return return_value;
     739                 :            : }
     740                 :            : #endif
     741                 :            : 
     742                 :            : // Ported from std/os/path.zig
     743                 :       9177 : Buf os_path_resolve(Buf **paths_ptr, size_t paths_len) {
     744                 :            : #if defined(ZIG_OS_WINDOWS)
     745                 :            :     return os_path_resolve_windows(paths_ptr, paths_len);
     746                 :            : #elif defined(ZIG_OS_POSIX)
     747                 :       9177 :     return os_path_resolve_posix(paths_ptr, paths_len);
     748                 :            : #else
     749                 :            : #error "missing os_path_resolve implementation"
     750                 :            : #endif
     751                 :            : }
     752                 :            : 
     753                 :         69 : Error os_fetch_file(FILE *f, Buf *out_buf) {
     754                 :            :     static const ssize_t buf_size = 0x2000;
     755                 :         69 :     buf_resize(out_buf, buf_size);
     756                 :         69 :     ssize_t actual_buf_len = 0;
     757                 :            : 
     758                 :            :     for (;;) {
     759                 :        201 :         size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
     760                 :        201 :         actual_buf_len += amt_read;
     761                 :            : 
     762         [ +  + ]:        201 :         if (amt_read != buf_size) {
     763         [ +  - ]:         69 :             if (feof(f)) {
     764                 :         69 :                 buf_resize(out_buf, actual_buf_len);
     765                 :         69 :                 return ErrorNone;
     766                 :            :             } else {
     767                 :          0 :                 return ErrorFileSystem;
     768                 :            :             }
     769                 :            :         }
     770                 :            : 
     771                 :        132 :         buf_resize(out_buf, actual_buf_len + buf_size);
     772                 :        132 :     }
     773                 :            :     zig_unreachable();
     774                 :            : }
     775                 :            : 
     776                 :         45 : Error os_file_exists(Buf *full_path, bool *result) {
     777                 :            : #if defined(ZIG_OS_WINDOWS)
     778                 :            :     *result = GetFileAttributes(buf_ptr(full_path)) != INVALID_FILE_ATTRIBUTES;
     779                 :            :     return ErrorNone;
     780                 :            : #else
     781                 :         45 :     *result = access(buf_ptr(full_path), F_OK) != -1;
     782                 :         45 :     return ErrorNone;
     783                 :            : #endif
     784                 :            : }
     785                 :            : 
     786                 :            : #if defined(ZIG_OS_POSIX)
     787                 :          0 : static Error os_exec_process_posix(ZigList<const char *> &args,
     788                 :            :         Termination *term, Buf *out_stderr, Buf *out_stdout)
     789                 :            : {
     790                 :            :     int stdin_pipe[2];
     791                 :            :     int stdout_pipe[2];
     792                 :            :     int stderr_pipe[2];
     793                 :            :     int err_pipe[2];
     794                 :            : 
     795                 :            :     int err;
     796         [ #  # ]:          0 :     if ((err = pipe(stdin_pipe)))
     797                 :          0 :         zig_panic("pipe failed");
     798         [ #  # ]:          0 :     if ((err = pipe(stdout_pipe)))
     799                 :          0 :         zig_panic("pipe failed");
     800         [ #  # ]:          0 :     if ((err = pipe(stderr_pipe)))
     801                 :          0 :         zig_panic("pipe failed");
     802         [ #  # ]:          0 :     if ((err = pipe(err_pipe)))
     803                 :          0 :         zig_panic("pipe failed");
     804                 :            : 
     805                 :          0 :     pid_t pid = fork();
     806         [ #  # ]:          0 :     if (pid == -1)
     807                 :          0 :         zig_panic("fork failed: %s", strerror(errno));
     808         [ #  # ]:          0 :     if (pid == 0) {
     809                 :            :         // child
     810         [ #  # ]:          0 :         if (dup2(stdin_pipe[0], STDIN_FILENO) == -1)
     811                 :          0 :             zig_panic("dup2 failed");
     812                 :            : 
     813         [ #  # ]:          0 :         if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1)
     814                 :          0 :             zig_panic("dup2 failed");
     815                 :            : 
     816         [ #  # ]:          0 :         if (dup2(stderr_pipe[1], STDERR_FILENO) == -1)
     817                 :          0 :             zig_panic("dup2 failed");
     818                 :            : 
     819                 :          0 :         const char **argv = allocate<const char *>(args.length + 1);
     820                 :          0 :         argv[args.length] = nullptr;
     821         [ #  # ]:          0 :         for (size_t i = 0; i < args.length; i += 1) {
     822                 :          0 :             argv[i] = args.at(i);
     823                 :            :         }
     824                 :          0 :         execvp(argv[0], const_cast<char * const *>(argv));
     825                 :          0 :         Error report_err = ErrorUnexpected;
     826         [ #  # ]:          0 :         if (errno == ENOENT) {
     827                 :          0 :             report_err = ErrorFileNotFound;
     828                 :            :         }
     829                 :          0 :         write(err_pipe[1], &report_err, sizeof(Error));
     830                 :          0 :         exit(1);
     831                 :            :     } else {
     832                 :            :         // parent
     833                 :          0 :         close(stdin_pipe[0]);
     834                 :          0 :         close(stdin_pipe[1]);
     835                 :          0 :         close(stdout_pipe[1]);
     836                 :          0 :         close(stderr_pipe[1]);
     837                 :            : 
     838                 :            :         int status;
     839                 :          0 :         waitpid(pid, &status, 0);
     840                 :          0 :         populate_termination(term, status);
     841                 :            : 
     842                 :          0 :         FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
     843                 :          0 :         FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
     844                 :          0 :         Error err1 = os_fetch_file(stdout_f, out_stdout);
     845                 :          0 :         Error err2 = os_fetch_file(stderr_f, out_stderr);
     846                 :            : 
     847                 :          0 :         fclose(stdout_f);
     848                 :          0 :         fclose(stderr_f);
     849                 :            : 
     850         [ #  # ]:          0 :         if (err1) return err1;
     851         [ #  # ]:          0 :         if (err2) return err2;
     852                 :            : 
     853                 :          0 :         Error child_err = ErrorNone;
     854                 :          0 :         write(err_pipe[1], &child_err, sizeof(Error));
     855                 :          0 :         close(err_pipe[1]);
     856                 :          0 :         read(err_pipe[0], &child_err, sizeof(Error));
     857                 :          0 :         close(err_pipe[0]);
     858                 :          0 :         return child_err;
     859                 :            :     }
     860                 :            : }
     861                 :            : #endif
     862                 :            : 
     863                 :            : #if defined(ZIG_OS_WINDOWS)
     864                 :            : 
     865                 :            : //static void win32_panic(const char *str) {
     866                 :            : //    DWORD err = GetLastError();
     867                 :            : //    LPSTR messageBuffer = nullptr;
     868                 :            : //    FormatMessageA(
     869                 :            : //        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
     870                 :            : //        NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
     871                 :            : //    zig_panic(str, messageBuffer);
     872                 :            : //    LocalFree(messageBuffer);
     873                 :            : //}
     874                 :            : 
     875                 :            : static Error os_exec_process_windows(ZigList<const char *> &args,
     876                 :            :         Termination *term, Buf *out_stderr, Buf *out_stdout)
     877                 :            : {
     878                 :            :     Buf command_line = BUF_INIT;
     879                 :            :     os_windows_create_command_line(&command_line, args);
     880                 :            : 
     881                 :            :     HANDLE g_hChildStd_IN_Rd = NULL;
     882                 :            :     HANDLE g_hChildStd_IN_Wr = NULL;
     883                 :            :     HANDLE g_hChildStd_OUT_Rd = NULL;
     884                 :            :     HANDLE g_hChildStd_OUT_Wr = NULL;
     885                 :            :     HANDLE g_hChildStd_ERR_Rd = NULL;
     886                 :            :     HANDLE g_hChildStd_ERR_Wr = NULL;
     887                 :            : 
     888                 :            :     SECURITY_ATTRIBUTES saAttr;
     889                 :            :     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
     890                 :            :     saAttr.bInheritHandle = TRUE;
     891                 :            :     saAttr.lpSecurityDescriptor = NULL;
     892                 :            : 
     893                 :            :     if (!CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0)) {
     894                 :            :         zig_panic("StdoutRd CreatePipe");
     895                 :            :     }
     896                 :            : 
     897                 :            :     if (!SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0)) {
     898                 :            :         zig_panic("Stdout SetHandleInformation");
     899                 :            :     }
     900                 :            : 
     901                 :            :     if (!CreatePipe(&g_hChildStd_ERR_Rd, &g_hChildStd_ERR_Wr, &saAttr, 0)) {
     902                 :            :         zig_panic("stderr CreatePipe");
     903                 :            :     }
     904                 :            : 
     905                 :            :     if (!SetHandleInformation(g_hChildStd_ERR_Rd, HANDLE_FLAG_INHERIT, 0)) {
     906                 :            :         zig_panic("stderr SetHandleInformation");
     907                 :            :     }
     908                 :            : 
     909                 :            :     if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) {
     910                 :            :         zig_panic("Stdin CreatePipe");
     911                 :            :     }
     912                 :            : 
     913                 :            :     if (!SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0)) {
     914                 :            :         zig_panic("Stdin SetHandleInformation");
     915                 :            :     }
     916                 :            : 
     917                 :            : 
     918                 :            :     PROCESS_INFORMATION piProcInfo = {0};
     919                 :            :     STARTUPINFO siStartInfo = {0};
     920                 :            :     siStartInfo.cb = sizeof(STARTUPINFO);
     921                 :            :     siStartInfo.hStdError = g_hChildStd_ERR_Wr;
     922                 :            :     siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
     923                 :            :     siStartInfo.hStdInput = g_hChildStd_IN_Rd;
     924                 :            :     siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
     925                 :            : 
     926                 :            :     const char *exe = args.at(0);
     927                 :            :     BOOL success = CreateProcess(exe, buf_ptr(&command_line), nullptr, nullptr, TRUE, 0, nullptr, nullptr,
     928                 :            :             &siStartInfo, &piProcInfo);
     929                 :            : 
     930                 :            :     if (!success) {
     931                 :            :         if (GetLastError() == ERROR_FILE_NOT_FOUND) {
     932                 :            :             CloseHandle(piProcInfo.hProcess);
     933                 :            :             CloseHandle(piProcInfo.hThread);
     934                 :            :             return ErrorFileNotFound;
     935                 :            :         }
     936                 :            :         zig_panic("CreateProcess failed. exe: %s command_line: %s", exe, buf_ptr(&command_line));
     937                 :            :     }
     938                 :            : 
     939                 :            :     if (!CloseHandle(g_hChildStd_IN_Wr)) {
     940                 :            :         zig_panic("stdinwr closehandle");
     941                 :            :     }
     942                 :            : 
     943                 :            :     CloseHandle(g_hChildStd_IN_Rd);
     944                 :            :     CloseHandle(g_hChildStd_ERR_Wr);
     945                 :            :     CloseHandle(g_hChildStd_OUT_Wr);
     946                 :            : 
     947                 :            :     static const size_t BUF_SIZE = 4 * 1024;
     948                 :            :     {
     949                 :            :         DWORD dwRead;
     950                 :            :         char chBuf[BUF_SIZE];
     951                 :            : 
     952                 :            :         buf_resize(out_stdout, 0);
     953                 :            :         for (;;) {
     954                 :            :             success = ReadFile( g_hChildStd_OUT_Rd, chBuf, BUF_SIZE, &dwRead, NULL);
     955                 :            :             if (!success || dwRead == 0) break;
     956                 :            : 
     957                 :            :             buf_append_mem(out_stdout, chBuf, dwRead);
     958                 :            :         }
     959                 :            :         CloseHandle(g_hChildStd_OUT_Rd);
     960                 :            :     }
     961                 :            :     {
     962                 :            :         DWORD dwRead;
     963                 :            :         char chBuf[BUF_SIZE];
     964                 :            : 
     965                 :            :         buf_resize(out_stderr, 0);
     966                 :            :         for (;;) {
     967                 :            :             success = ReadFile( g_hChildStd_ERR_Rd, chBuf, BUF_SIZE, &dwRead, NULL);
     968                 :            :             if (!success || dwRead == 0) break;
     969                 :            : 
     970                 :            :             buf_append_mem(out_stderr, chBuf, dwRead);
     971                 :            :         }
     972                 :            :         CloseHandle(g_hChildStd_ERR_Rd);
     973                 :            :     }
     974                 :            : 
     975                 :            :     WaitForSingleObject(piProcInfo.hProcess, INFINITE);
     976                 :            : 
     977                 :            :     DWORD exit_code;
     978                 :            :     if (!GetExitCodeProcess(piProcInfo.hProcess, &exit_code)) {
     979                 :            :         zig_panic("GetExitCodeProcess failed");
     980                 :            :     }
     981                 :            :     term->how = TerminationIdClean;
     982                 :            :     term->code = exit_code;
     983                 :            : 
     984                 :            :     CloseHandle(piProcInfo.hProcess);
     985                 :            :     CloseHandle(piProcInfo.hThread);
     986                 :            : 
     987                 :            :     return ErrorNone;
     988                 :            : }
     989                 :            : #endif
     990                 :            : 
     991                 :          0 : Error os_execv(const char *exe, const char **argv) {
     992                 :            : #if defined(ZIG_OS_WINDOWS)
     993                 :            :     return ErrorUnsupportedOperatingSystem;
     994                 :            : #else
     995                 :          0 :     execv(exe, (char *const *)argv);
     996      [ #  #  # ]:          0 :     switch (errno) {
     997                 :          0 :         case ENOMEM:
     998                 :          0 :             return ErrorSystemResources;
     999                 :          0 :         case EIO:
    1000                 :          0 :             return ErrorFileSystem;
    1001                 :          0 :         default:
    1002                 :          0 :             return ErrorUnexpected;
    1003                 :            :     }
    1004                 :            : #endif
    1005                 :            : }
    1006                 :            : 
    1007                 :          0 : Error os_exec_process(ZigList<const char *> &args,
    1008                 :            :         Termination *term, Buf *out_stderr, Buf *out_stdout)
    1009                 :            : {
    1010                 :            : #if defined(ZIG_OS_WINDOWS)
    1011                 :            :     return os_exec_process_windows(args, term, out_stderr, out_stdout);
    1012                 :            : #elif defined(ZIG_OS_POSIX)
    1013                 :          0 :     return os_exec_process_posix(args, term, out_stderr, out_stdout);
    1014                 :            : #else
    1015                 :            : #error "missing os_exec_process implementation"
    1016                 :            : #endif
    1017                 :            : }
    1018                 :            : 
    1019                 :         24 : Error os_write_file(Buf *full_path, Buf *contents) {
    1020                 :         24 :     FILE *f = fopen(buf_ptr(full_path), "wb");
    1021         [ -  + ]:         24 :     if (!f) {
    1022                 :          0 :         zig_panic("os_write_file failed for %s", buf_ptr(full_path));
    1023                 :            :     }
    1024                 :         24 :     size_t amt_written = fwrite(buf_ptr(contents), 1, buf_len(contents), f);
    1025         [ -  + ]:         24 :     if (amt_written != (size_t)buf_len(contents))
    1026                 :          0 :         zig_panic("write failed: %s", strerror(errno));
    1027         [ -  + ]:         24 :     if (fclose(f))
    1028                 :          0 :         zig_panic("close failed");
    1029                 :         24 :     return ErrorNone;
    1030                 :            : }
    1031                 :            : 
    1032                 :          0 : Error os_copy_file(Buf *src_path, Buf *dest_path) {
    1033                 :          0 :     FILE *src_f = fopen(buf_ptr(src_path), "rb");
    1034         [ #  # ]:          0 :     if (!src_f) {
    1035                 :          0 :         int err = errno;
    1036         [ #  # ]:          0 :         if (err == ENOENT) {
    1037                 :          0 :             return ErrorFileNotFound;
    1038 [ #  # ][ #  # ]:          0 :         } else if (err == EACCES || err == EPERM) {
    1039                 :          0 :             return ErrorAccess;
    1040                 :            :         } else {
    1041                 :          0 :             return ErrorFileSystem;
    1042                 :            :         }
    1043                 :            :     }
    1044                 :          0 :     FILE *dest_f = fopen(buf_ptr(dest_path), "wb");
    1045         [ #  # ]:          0 :     if (!dest_f) {
    1046                 :          0 :         int err = errno;
    1047         [ #  # ]:          0 :         if (err == ENOENT) {
    1048                 :          0 :             fclose(src_f);
    1049                 :          0 :             return ErrorFileNotFound;
    1050 [ #  # ][ #  # ]:          0 :         } else if (err == EACCES || err == EPERM) {
    1051                 :          0 :             fclose(src_f);
    1052                 :          0 :             return ErrorAccess;
    1053                 :            :         } else {
    1054                 :          0 :             fclose(src_f);
    1055                 :          0 :             return ErrorFileSystem;
    1056                 :            :         }
    1057                 :            :     }
    1058                 :            : 
    1059                 :            :     static const size_t buf_size = 2048;
    1060                 :            :     char buf[buf_size];
    1061                 :            :     for (;;) {
    1062                 :          0 :         size_t amt_read = fread(buf, 1, buf_size, src_f);
    1063         [ #  # ]:          0 :         if (amt_read != buf_size) {
    1064         [ #  # ]:          0 :             if (ferror(src_f)) {
    1065                 :          0 :                 fclose(src_f);
    1066                 :          0 :                 fclose(dest_f);
    1067                 :          0 :                 return ErrorFileSystem;
    1068                 :            :             }
    1069                 :            :         }
    1070                 :          0 :         size_t amt_written = fwrite(buf, 1, amt_read, dest_f);
    1071         [ #  # ]:          0 :         if (amt_written != amt_read) {
    1072                 :          0 :             fclose(src_f);
    1073                 :          0 :             fclose(dest_f);
    1074                 :          0 :             return ErrorFileSystem;
    1075                 :            :         }
    1076         [ #  # ]:          0 :         if (feof(src_f)) {
    1077                 :          0 :             fclose(src_f);
    1078                 :          0 :             fclose(dest_f);
    1079                 :          0 :             return ErrorNone;
    1080                 :            :         }
    1081                 :          0 :     }
    1082                 :            : }
    1083                 :            : 
    1084                 :         69 : Error os_fetch_file_path(Buf *full_path, Buf *out_contents) {
    1085                 :         69 :     FILE *f = fopen(buf_ptr(full_path), "rb");
    1086         [ -  + ]:         69 :     if (!f) {
    1087   [ #  #  #  #  :          0 :         switch (errno) {
                   #  # ]
    1088                 :          0 :             case EACCES:
    1089                 :          0 :                 return ErrorAccess;
    1090                 :          0 :             case EINTR:
    1091                 :          0 :                 return ErrorInterrupted;
    1092                 :          0 :             case EINVAL:
    1093                 :          0 :                 return ErrorInvalidFilename;
    1094                 :          0 :             case ENFILE:
    1095                 :            :             case ENOMEM:
    1096                 :          0 :                 return ErrorSystemResources;
    1097                 :          0 :             case ENOENT:
    1098                 :          0 :                 return ErrorFileNotFound;
    1099                 :          0 :             default:
    1100                 :          0 :                 return ErrorFileSystem;
    1101                 :            :         }
    1102                 :            :     }
    1103                 :         69 :     Error result = os_fetch_file(f, out_contents);
    1104                 :         69 :     fclose(f);
    1105                 :         69 :     return result;
    1106                 :            : }
    1107                 :            : 
    1108                 :          2 : Error os_get_cwd(Buf *out_cwd) {
    1109                 :            : #if defined(ZIG_OS_WINDOWS)
    1110                 :            :     char buf[4096];
    1111                 :            :     if (GetCurrentDirectory(4096, buf) == 0) {
    1112                 :            :         zig_panic("GetCurrentDirectory failed");
    1113                 :            :     }
    1114                 :            :     buf_init_from_str(out_cwd, buf);
    1115                 :            :     return ErrorNone;
    1116                 :            : #elif defined(ZIG_OS_POSIX)
    1117                 :            :     char buf[PATH_MAX];
    1118                 :          2 :     char *res = getcwd(buf, PATH_MAX);
    1119         [ -  + ]:          2 :     if (res == nullptr) {
    1120                 :          0 :         zig_panic("unable to get cwd: %s", strerror(errno));
    1121                 :            :     }
    1122                 :          2 :     buf_init_from_str(out_cwd, res);
    1123                 :          2 :     return ErrorNone;
    1124                 :            : #else
    1125                 :            : #error "missing os_get_cwd implementation"
    1126                 :            : #endif
    1127                 :            : }
    1128                 :            : 
    1129                 :            : #if defined(ZIG_OS_WINDOWS)
    1130                 :            : #define is_wprefix(s, prefix) \
    1131                 :            :     (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0)
    1132                 :            : static bool is_stderr_cyg_pty(void) {
    1133                 :            :     HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
    1134                 :            :     if (stderr_handle == INVALID_HANDLE_VALUE)
    1135                 :            :         return false;
    1136                 :            : 
    1137                 :            :     int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH;
    1138                 :            :     FILE_NAME_INFO *nameinfo;
    1139                 :            :     WCHAR *p = NULL;
    1140                 :            : 
    1141                 :            :     // Cygwin/msys's pty is a pipe.
    1142                 :            :     if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) {
    1143                 :            :         return 0;
    1144                 :            :     }
    1145                 :            :     nameinfo = (FILE_NAME_INFO *)allocate<char>(size);
    1146                 :            :     if (nameinfo == NULL) {
    1147                 :            :         return 0;
    1148                 :            :     }
    1149                 :            :     // Check the name of the pipe:
    1150                 :            :     // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master'
    1151                 :            :     if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) {
    1152                 :            :         nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0';
    1153                 :            :         p = nameinfo->FileName;
    1154                 :            :         if (is_wprefix(p, L"\\cygwin-")) {      /* Cygwin */
    1155                 :            :             p += 8;
    1156                 :            :         } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */
    1157                 :            :             p += 6;
    1158                 :            :         } else {
    1159                 :            :             p = NULL;
    1160                 :            :         }
    1161                 :            :         if (p != NULL) {
    1162                 :            :             while (*p && isxdigit(*p))  /* Skip 16-digit hexadecimal. */
    1163                 :            :                 ++p;
    1164                 :            :             if (is_wprefix(p, L"-pty")) {
    1165                 :            :                 p += 4;
    1166                 :            :             } else {
    1167                 :            :                 p = NULL;
    1168                 :            :             }
    1169                 :            :         }
    1170                 :            :         if (p != NULL) {
    1171                 :            :             while (*p && isdigit(*p))   /* Skip pty number. */
    1172                 :            :                 ++p;
    1173                 :            :             if (is_wprefix(p, L"-from-master")) {
    1174                 :            :                 //p += 12;
    1175                 :            :             } else if (is_wprefix(p, L"-to-master")) {
    1176                 :            :                 //p += 10;
    1177                 :            :             } else {
    1178                 :            :                 p = NULL;
    1179                 :            :             }
    1180                 :            :         }
    1181                 :            :     }
    1182                 :            :     free(nameinfo);
    1183                 :            :     return (p != NULL);
    1184                 :            : }
    1185                 :            : #endif
    1186                 :            : 
    1187                 :          0 : bool os_stderr_tty(void) {
    1188                 :            : #if defined(ZIG_OS_WINDOWS)
    1189                 :            :     return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty();
    1190                 :            : #elif defined(ZIG_OS_POSIX)
    1191                 :          0 :     return isatty(STDERR_FILENO) != 0;
    1192                 :            : #else
    1193                 :            : #error "missing os_stderr_tty implementation"
    1194                 :            : #endif
    1195                 :            : }
    1196                 :            : 
    1197                 :         35 : Error os_delete_file(Buf *path) {
    1198         [ -  + ]:         35 :     if (remove(buf_ptr(path))) {
    1199                 :          0 :         return ErrorFileSystem;
    1200                 :            :     } else {
    1201                 :         35 :         return ErrorNone;
    1202                 :            :     }
    1203                 :            : }
    1204                 :            : 
    1205                 :         35 : Error os_rename(Buf *src_path, Buf *dest_path) {
    1206         [ -  + ]:         35 :     if (buf_eql_buf(src_path, dest_path)) {
    1207                 :          0 :         return ErrorNone;
    1208                 :            :     }
    1209                 :            : #if defined(ZIG_OS_WINDOWS)
    1210                 :            :     if (!MoveFileExA(buf_ptr(src_path), buf_ptr(dest_path), MOVEFILE_REPLACE_EXISTING)) {
    1211                 :            :         return ErrorFileSystem;
    1212                 :            :     }
    1213                 :            : #else
    1214         [ -  + ]:         35 :     if (rename(buf_ptr(src_path), buf_ptr(dest_path)) == -1) {
    1215                 :          0 :         return ErrorFileSystem;
    1216                 :            :     }
    1217                 :            : #endif
    1218                 :         35 :     return ErrorNone;
    1219                 :            : }
    1220                 :            : 
    1221                 :            : #if defined(ZIG_OS_WINDOWS)
    1222                 :            : static void windows_filetime_to_os_timestamp(FILETIME *ft, OsTimeStamp *mtime) {
    1223                 :            :     mtime->sec = (((ULONGLONG) ft->dwHighDateTime) << 32) + ft->dwLowDateTime;
    1224                 :            :     mtime->nsec = 0;
    1225                 :            : }
    1226                 :            : #endif
    1227                 :            : 
    1228                 :       2952 : OsTimeStamp os_timestamp_calendar(void) {
    1229                 :            :     OsTimeStamp result;
    1230                 :            : #if defined(ZIG_OS_WINDOWS)
    1231                 :            :     FILETIME ft;
    1232                 :            :     GetSystemTimeAsFileTime(&ft);
    1233                 :            :     windows_filetime_to_os_timestamp(&ft, &result);
    1234                 :            : #elif defined(__MACH__)
    1235                 :            :     mach_timespec_t mts;
    1236                 :            : 
    1237                 :            :     kern_return_t err = clock_get_time(macos_calendar_clock, &mts);
    1238                 :            :     assert(!err);
    1239                 :            : 
    1240                 :            :     result.sec = mts.tv_sec;
    1241                 :            :     result.nsec = mts.tv_nsec;
    1242                 :            : #else
    1243                 :            :     struct timespec tms;
    1244                 :       2952 :     clock_gettime(CLOCK_REALTIME, &tms);
    1245                 :            : 
    1246                 :       2952 :     result.sec = tms.tv_sec;
    1247                 :       2952 :     result.nsec = tms.tv_nsec;
    1248                 :            : #endif
    1249                 :       2952 :     return result;
    1250                 :            : }
    1251                 :            : 
    1252                 :        310 : OsTimeStamp os_timestamp_monotonic(void) {
    1253                 :            :     OsTimeStamp result;
    1254                 :            : #if defined(ZIG_OS_WINDOWS)
    1255                 :            :     uint64_t counts;
    1256                 :            :     QueryPerformanceCounter((LARGE_INTEGER*)&counts);
    1257                 :            :     result.sec = counts / windows_perf_freq;
    1258                 :            :     result.nsec = (counts % windows_perf_freq) * 1000000000u / windows_perf_freq;
    1259                 :            : #elif defined(__MACH__)
    1260                 :            :     mach_timespec_t mts;
    1261                 :            : 
    1262                 :            :     kern_return_t err = clock_get_time(macos_monotonic_clock, &mts);
    1263                 :            :     assert(!err);
    1264                 :            : 
    1265                 :            :     result.sec = mts.tv_sec;
    1266                 :            :     result.nsec = mts.tv_nsec;
    1267                 :            : #else
    1268                 :            :     struct timespec tms;
    1269                 :        310 :     clock_gettime(CLOCK_MONOTONIC, &tms);
    1270                 :            : 
    1271                 :        310 :     result.sec = tms.tv_sec;
    1272                 :        310 :     result.nsec = tms.tv_nsec;
    1273                 :            : #endif
    1274                 :        310 :     return result;
    1275                 :            : }
    1276                 :            : 
    1277                 :        279 : Error os_make_path(Buf *path) {
    1278                 :        279 :     Buf resolved_path = os_path_resolve(&path, 1);
    1279                 :            : 
    1280                 :        279 :     size_t end_index = buf_len(&resolved_path);
    1281                 :            :     Error err;
    1282                 :            :     while (true) {
    1283         [ +  + ]:        570 :         if ((err = os_make_dir(buf_slice(&resolved_path, 0, end_index)))) {
    1284         [ +  + ]:        194 :             if (err == ErrorPathAlreadyExists) {
    1285         [ +  - ]:        188 :                 if (end_index == buf_len(&resolved_path))
    1286                 :        188 :                     return ErrorNone;
    1287         [ +  - ]:          6 :             } else if (err == ErrorFileNotFound) {
    1288                 :            :                 // march end_index backward until next path component
    1289                 :            :                 while (true) {
    1290                 :        202 :                     end_index -= 1;
    1291         [ +  + ]:        208 :                     if (os_is_sep(buf_ptr(&resolved_path)[end_index]))
    1292                 :          6 :                         break;
    1293                 :            :                 }
    1294                 :          6 :                 continue;
    1295                 :            :             } else {
    1296                 :          0 :                 return err;
    1297                 :            :             }
    1298                 :            :         }
    1299         [ +  + ]:         97 :         if (end_index == buf_len(&resolved_path))
    1300                 :         91 :             return ErrorNone;
    1301                 :            :         // march end_index forward until next path component
    1302                 :            :         while (true) {
    1303                 :        202 :             end_index += 1;
    1304 [ +  + ][ +  + ]:        208 :             if (end_index == buf_len(&resolved_path) || os_is_sep(buf_ptr(&resolved_path)[end_index]))
                 [ +  + ]
    1305                 :          6 :                 break;
    1306                 :            :         }
    1307                 :            :     }
    1308                 :            :     return ErrorNone;
    1309                 :            : }
    1310                 :            : 
    1311                 :        291 : Error os_make_dir(Buf *path) {
    1312                 :            : #if defined(ZIG_OS_WINDOWS)
    1313                 :            :     if (!CreateDirectory(buf_ptr(path), NULL)) {
    1314                 :            :         if (GetLastError() == ERROR_ALREADY_EXISTS)
    1315                 :            :             return ErrorPathAlreadyExists;
    1316                 :            :         if (GetLastError() == ERROR_PATH_NOT_FOUND)
    1317                 :            :             return ErrorFileNotFound;
    1318                 :            :         if (GetLastError() == ERROR_ACCESS_DENIED)
    1319                 :            :             return ErrorAccess;
    1320                 :            :         return ErrorUnexpected;
    1321                 :            :     }
    1322                 :            :     return ErrorNone;
    1323                 :            : #else
    1324         [ +  + ]:        291 :     if (mkdir(buf_ptr(path), 0755) == -1) {
    1325         [ +  + ]:        194 :         if (errno == EEXIST)
    1326                 :        188 :             return ErrorPathAlreadyExists;
    1327         [ +  - ]:          6 :         if (errno == ENOENT)
    1328                 :          6 :             return ErrorFileNotFound;
    1329         [ #  # ]:          0 :         if (errno == EACCES)
    1330                 :          0 :             return ErrorAccess;
    1331                 :          0 :         return ErrorUnexpected;
    1332                 :            :     }
    1333                 :         97 :     return ErrorNone;
    1334                 :            : #endif
    1335                 :            : }
    1336                 :            : 
    1337                 :         18 : static void init_rand() {
    1338                 :            : #if defined(ZIG_OS_WINDOWS)
    1339                 :            :     char bytes[sizeof(unsigned)];
    1340                 :            :     unsigned seed;
    1341                 :            :     RtlGenRandom(bytes, sizeof(unsigned));
    1342                 :            :     memcpy(&seed, bytes, sizeof(unsigned));
    1343                 :            :     srand(seed);
    1344                 :            : #elif defined(ZIG_OS_LINUX)
    1345                 :         18 :     srand(*((unsigned*)getauxval(AT_RANDOM)));
    1346                 :            : #else
    1347                 :            :     int fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC);
    1348                 :            :     if (fd == -1) {
    1349                 :            :         zig_panic("unable to open /dev/urandom");
    1350                 :            :     }
    1351                 :            :     char bytes[sizeof(unsigned)];
    1352                 :            :     ssize_t amt_read;
    1353                 :            :     while ((amt_read = read(fd, bytes, sizeof(unsigned))) == -1) {
    1354                 :            :         if (errno == EINTR) continue;
    1355                 :            :         zig_panic("unable to read /dev/urandom");
    1356                 :            :     }
    1357                 :            :     if (amt_read != sizeof(unsigned)) {
    1358                 :            :         zig_panic("unable to read enough bytes from /dev/urandom");
    1359                 :            :     }
    1360                 :            :     close(fd);
    1361                 :            :     unsigned seed;
    1362                 :            :     memcpy(&seed, bytes, sizeof(unsigned));
    1363                 :            :     srand(seed);
    1364                 :            : #endif
    1365                 :         18 : }
    1366                 :            : 
    1367                 :         18 : int os_init(void) {
    1368                 :         18 :     init_rand();
    1369                 :            : #if defined(ZIG_OS_WINDOWS)
    1370                 :            :     _setmode(fileno(stdout), _O_BINARY);
    1371                 :            :     _setmode(fileno(stderr), _O_BINARY);
    1372                 :            :     if (!QueryPerformanceFrequency((LARGE_INTEGER*)&windows_perf_freq)) {
    1373                 :            :         return ErrorSystemResources;
    1374                 :            :     }
    1375                 :            : #elif defined(__MACH__)
    1376                 :            :     host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &macos_monotonic_clock);
    1377                 :            :     host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &macos_calendar_clock);
    1378                 :            : #endif
    1379                 :            : #if defined(ZIG_OS_POSIX)
    1380                 :            :     // Raise the open file descriptor limit.
    1381                 :            :     // Code lifted from node.js
    1382                 :            :     struct rlimit lim;
    1383 [ +  + ][ +  + ]:         18 :     if (getrlimit(RLIMIT_NOFILE, &lim) == 0 && lim.rlim_cur != lim.rlim_max) {
                 [ +  - ]
    1384                 :            :         // Do a binary search for the limit.
    1385                 :          2 :         rlim_t min = lim.rlim_cur;
    1386                 :          2 :         rlim_t max = 1 << 20;
    1387                 :            :         // But if there's a defined upper bound, don't search, just set it.
    1388         [ +  - ]:          2 :         if (lim.rlim_max != RLIM_INFINITY) {
    1389                 :          2 :             min = lim.rlim_max;
    1390                 :          2 :             max = lim.rlim_max;
    1391                 :            :         }
    1392                 :          2 :         do {
    1393                 :          2 :             lim.rlim_cur = min + (max - min) / 2;
    1394         [ -  + ]:          2 :             if (setrlimit(RLIMIT_NOFILE, &lim)) {
    1395                 :          0 :                 max = lim.rlim_cur;
    1396                 :            :             } else {
    1397                 :          2 :                 min = lim.rlim_cur;
    1398                 :            :             }
    1399         [ -  + ]:          2 :         } while (min + 1 < max);
    1400                 :            :     }
    1401                 :            : #endif
    1402                 :         18 :     return 0;
    1403                 :            : }
    1404                 :            : 
    1405                 :         78 : Error os_self_exe_path(Buf *out_path) {
    1406                 :            : #if defined(ZIG_OS_WINDOWS)
    1407                 :            :     buf_resize(out_path, 256);
    1408                 :            :     for (;;) {
    1409                 :            :         DWORD copied_amt = GetModuleFileName(nullptr, buf_ptr(out_path), buf_len(out_path));
    1410                 :            :         if (copied_amt <= 0) {
    1411                 :            :             return ErrorFileNotFound;
    1412                 :            :         }
    1413                 :            :         if (copied_amt < buf_len(out_path)) {
    1414                 :            :             buf_resize(out_path, copied_amt);
    1415                 :            :             return ErrorNone;
    1416                 :            :         }
    1417                 :            :         buf_resize(out_path, buf_len(out_path) * 2);
    1418                 :            :     }
    1419                 :            : 
    1420                 :            : #elif defined(ZIG_OS_DARWIN)
    1421                 :            :     // How long is the executable's path?
    1422                 :            :     uint32_t u32_len = 0;
    1423                 :            :     int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
    1424                 :            :     assert(ret1 != 0);
    1425                 :            : 
    1426                 :            :     Buf *tmp = buf_alloc_fixed(u32_len);
    1427                 :            : 
    1428                 :            :     // Fill the executable path.
    1429                 :            :     int ret2 = _NSGetExecutablePath(buf_ptr(tmp), &u32_len);
    1430                 :            :     assert(ret2 == 0);
    1431                 :            : 
    1432                 :            :     // According to libuv project, PATH_MAX*2 works around a libc bug where
    1433                 :            :     // the resolved path is sometimes bigger than PATH_MAX.
    1434                 :            :     buf_resize(out_path, PATH_MAX*2);
    1435                 :            :     char *real_path = realpath(buf_ptr(tmp), buf_ptr(out_path));
    1436                 :            :     if (!real_path) {
    1437                 :            :         buf_init_from_buf(out_path, tmp);
    1438                 :            :         return ErrorNone;
    1439                 :            :     }
    1440                 :            : 
    1441                 :            :     // Resize out_path for the correct length.
    1442                 :            :     buf_resize(out_path, strlen(buf_ptr(out_path)));
    1443                 :            : 
    1444                 :            :     return ErrorNone;
    1445                 :            : #elif defined(ZIG_OS_LINUX)
    1446                 :         78 :     buf_resize(out_path, PATH_MAX);
    1447                 :         78 :     ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
    1448         [ -  + ]:         78 :     if (amt == -1) {
    1449                 :          0 :         return ErrorUnexpected;
    1450                 :            :     }
    1451                 :         78 :     buf_resize(out_path, amt);
    1452                 :         78 :     return ErrorNone;
    1453                 :            : #elif defined(ZIG_OS_FREEBSD)
    1454                 :            :     buf_resize(out_path, PATH_MAX);
    1455                 :            :     int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
    1456                 :            :     size_t cb = PATH_MAX;
    1457                 :            :     if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
    1458                 :            :         return ErrorUnexpected;
    1459                 :            :     }
    1460                 :            :     buf_resize(out_path, cb - 1);
    1461                 :            :     return ErrorNone;
    1462                 :            : #elif defined(ZIG_OS_NETBSD)
    1463                 :            :     buf_resize(out_path, PATH_MAX);
    1464                 :            :     int mib[4] = { CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
    1465                 :            :     size_t cb = PATH_MAX;
    1466                 :            :     if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
    1467                 :            :         return ErrorUnexpected;
    1468                 :            :     }
    1469                 :            :     buf_resize(out_path, cb - 1);
    1470                 :            :     return ErrorNone;
    1471                 :            : #endif
    1472                 :            :     return ErrorFileNotFound;
    1473                 :            : }
    1474                 :            : 
    1475                 :            : #define VT_RED "\x1b[31;1m"
    1476                 :            : #define VT_GREEN "\x1b[32;1m"
    1477                 :            : #define VT_CYAN "\x1b[36;1m"
    1478                 :            : #define VT_WHITE "\x1b[37;1m"
    1479                 :            : #define VT_BOLD "\x1b[0;1m"
    1480                 :            : #define VT_RESET "\x1b[0m"
    1481                 :            : 
    1482                 :          0 : static void set_color_posix(TermColor color) {
    1483   [ #  #  #  #  :          0 :     switch (color) {
                #  #  # ]
    1484                 :          0 :         case TermColorRed:
    1485                 :          0 :             fprintf(stderr, VT_RED);
    1486                 :          0 :             break;
    1487                 :          0 :         case TermColorGreen:
    1488                 :          0 :             fprintf(stderr, VT_GREEN);
    1489                 :          0 :             break;
    1490                 :          0 :         case TermColorCyan:
    1491                 :          0 :             fprintf(stderr, VT_CYAN);
    1492                 :          0 :             break;
    1493                 :          0 :         case TermColorWhite:
    1494                 :          0 :             fprintf(stderr, VT_WHITE);
    1495                 :          0 :             break;
    1496                 :          0 :         case TermColorBold:
    1497                 :          0 :             fprintf(stderr, VT_BOLD);
    1498                 :          0 :             break;
    1499                 :          0 :         case TermColorReset:
    1500                 :          0 :             fprintf(stderr, VT_RESET);
    1501                 :          0 :             break;
    1502                 :            :     }
    1503                 :          0 : }
    1504                 :            : 
    1505                 :            : 
    1506                 :            : #if defined(ZIG_OS_WINDOWS)
    1507                 :            : bool got_orig_console_attrs = false;
    1508                 :            : WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE;
    1509                 :            : #endif
    1510                 :            : 
    1511                 :          0 : void os_stderr_set_color(TermColor color) {
    1512                 :            : #if defined(ZIG_OS_WINDOWS)
    1513                 :            :     if (is_stderr_cyg_pty()) {
    1514                 :            :         set_color_posix(color);
    1515                 :            :         return;
    1516                 :            :     }
    1517                 :            :     HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
    1518                 :            :     if (stderr_handle == INVALID_HANDLE_VALUE)
    1519                 :            :         zig_panic("unable to get stderr handle");
    1520                 :            :     fflush(stderr);
    1521                 :            : 
    1522                 :            :     if (!got_orig_console_attrs) {
    1523                 :            :         got_orig_console_attrs = true;
    1524                 :            :         CONSOLE_SCREEN_BUFFER_INFO info;
    1525                 :            :         if (GetConsoleScreenBufferInfo(stderr_handle, &info)) {
    1526                 :            :             original_console_attributes = info.wAttributes;
    1527                 :            :         }
    1528                 :            :     }
    1529                 :            : 
    1530                 :            :     switch (color) {
    1531                 :            :         case TermColorRed:
    1532                 :            :             SetConsoleTextAttribute(stderr_handle, FOREGROUND_RED|FOREGROUND_INTENSITY);
    1533                 :            :             break;
    1534                 :            :         case TermColorGreen:
    1535                 :            :             SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_INTENSITY);
    1536                 :            :             break;
    1537                 :            :         case TermColorCyan:
    1538                 :            :             SetConsoleTextAttribute(stderr_handle, FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
    1539                 :            :             break;
    1540                 :            :         case TermColorWhite:
    1541                 :            :         case TermColorBold:
    1542                 :            :             SetConsoleTextAttribute(stderr_handle,
    1543                 :            :                 FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_INTENSITY);
    1544                 :            :             break;
    1545                 :            :         case TermColorReset:
    1546                 :            :             SetConsoleTextAttribute(stderr_handle, original_console_attributes);
    1547                 :            :             break;
    1548                 :            :     }
    1549                 :            : #else
    1550                 :          0 :     set_color_posix(color);
    1551                 :            : #endif
    1552                 :          0 : }
    1553                 :            : 
    1554                 :          0 : Error os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
    1555                 :            : #if defined(ZIG_OS_WINDOWS)
    1556                 :            :     buf_resize(output_buf, 0);
    1557                 :            :     buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
    1558                 :            :     switch (platform_type) {
    1559                 :            :     case ZigLLVM_x86:
    1560                 :            :         buf_append_str(output_buf, "x86\\");
    1561                 :            :         break;
    1562                 :            :     case ZigLLVM_x86_64:
    1563                 :            :         buf_append_str(output_buf, "x64\\");
    1564                 :            :         break;
    1565                 :            :     case ZigLLVM_arm:
    1566                 :            :         buf_append_str(output_buf, "arm\\");
    1567                 :            :         break;
    1568                 :            :     default:
    1569                 :            :         zig_panic("Attempted to use vcruntime for non-supported platform.");
    1570                 :            :     }
    1571                 :            :     Buf* tmp_buf = buf_alloc();
    1572                 :            :     buf_init_from_buf(tmp_buf, output_buf);
    1573                 :            :     buf_append_str(tmp_buf, "ucrt.lib");
    1574                 :            :     if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
    1575                 :            :         return ErrorNone;
    1576                 :            :     }
    1577                 :            :     else {
    1578                 :            :         buf_resize(output_buf, 0);
    1579                 :            :         return ErrorFileNotFound;
    1580                 :            :     }
    1581                 :            : #else
    1582                 :          0 :     return ErrorFileNotFound;
    1583                 :            : #endif
    1584                 :            : }
    1585                 :            : 
    1586                 :          0 : Error os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
    1587                 :            : #if defined(ZIG_OS_WINDOWS)
    1588                 :            :     buf_resize(output_buf, 0);
    1589                 :            :     buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
    1590                 :            :     if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
    1591                 :            :         return ErrorNone;
    1592                 :            :     }
    1593                 :            :     else {
    1594                 :            :         buf_resize(output_buf, 0);
    1595                 :            :         return ErrorFileNotFound;
    1596                 :            :     }
    1597                 :            : #else
    1598                 :          0 :     return ErrorFileNotFound;
    1599                 :            : #endif
    1600                 :            : }
    1601                 :            : 
    1602                 :          0 : Error os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
    1603                 :            : #if defined(ZIG_OS_WINDOWS)
    1604                 :            :     {
    1605                 :            :         buf_resize(output_buf, 0);
    1606                 :            :         buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
    1607                 :            :         switch (platform_type) {
    1608                 :            :         case ZigLLVM_x86:
    1609                 :            :             buf_append_str(output_buf, "x86\\");
    1610                 :            :             break;
    1611                 :            :         case ZigLLVM_x86_64:
    1612                 :            :             buf_append_str(output_buf, "x64\\");
    1613                 :            :             break;
    1614                 :            :         case ZigLLVM_arm:
    1615                 :            :             buf_append_str(output_buf, "arm\\");
    1616                 :            :             break;
    1617                 :            :         default:
    1618                 :            :             zig_panic("Attempted to use vcruntime for non-supported platform.");
    1619                 :            :         }
    1620                 :            :         Buf* tmp_buf = buf_alloc();
    1621                 :            :         buf_init_from_buf(tmp_buf, output_buf);
    1622                 :            :         buf_append_str(tmp_buf, "kernel32.lib");
    1623                 :            :         if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
    1624                 :            :             return ErrorNone;
    1625                 :            :         }
    1626                 :            :     }
    1627                 :            :     {
    1628                 :            :         buf_resize(output_buf, 0);
    1629                 :            :         buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
    1630                 :            :         switch (platform_type) {
    1631                 :            :         case ZigLLVM_x86:
    1632                 :            :             buf_append_str(output_buf, "x86\\");
    1633                 :            :             break;
    1634                 :            :         case ZigLLVM_x86_64:
    1635                 :            :             buf_append_str(output_buf, "x64\\");
    1636                 :            :             break;
    1637                 :            :         case ZigLLVM_arm:
    1638                 :            :             buf_append_str(output_buf, "arm\\");
    1639                 :            :             break;
    1640                 :            :         default:
    1641                 :            :             zig_panic("Attempted to use vcruntime for non-supported platform.");
    1642                 :            :         }
    1643                 :            :         Buf* tmp_buf = buf_alloc();
    1644                 :            :         buf_init_from_buf(tmp_buf, output_buf);
    1645                 :            :         buf_append_str(tmp_buf, "kernel32.lib");
    1646                 :            :         if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
    1647                 :            :             return ErrorNone;
    1648                 :            :         }
    1649                 :            :     }
    1650                 :            :     return ErrorFileNotFound;
    1651                 :            : #else
    1652                 :          0 :     return ErrorFileNotFound;
    1653                 :            : #endif
    1654                 :            : }
    1655                 :            : 
    1656                 :            : #if defined(ZIG_OS_WINDOWS)
    1657                 :            : // Ported from std/unicode.zig
    1658                 :            : struct Utf16LeIterator {
    1659                 :            :     uint8_t *bytes;
    1660                 :            :     size_t i;
    1661                 :            : };
    1662                 :            : 
    1663                 :            : // Ported from std/unicode.zig
    1664                 :            : static Utf16LeIterator Utf16LeIterator_init(WCHAR *ptr) {
    1665                 :            :     return {(uint8_t*)ptr, 0};
    1666                 :            : }
    1667                 :            : 
    1668                 :            : // Ported from std/unicode.zig
    1669                 :            : static Optional<uint32_t> Utf16LeIterator_nextCodepoint(Utf16LeIterator *it) {
    1670                 :            :     if (it->bytes[it->i] == 0 && it->bytes[it->i + 1] == 0)
    1671                 :            :         return {};
    1672                 :            :     uint32_t c0 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
    1673                 :            :     if ((c0 & ~((uint32_t)0x03ff)) == 0xd800) {
    1674                 :            :         // surrogate pair
    1675                 :            :         it->i += 2;
    1676                 :            :         assert(it->bytes[it->i] != 0 || it->bytes[it->i + 1] != 0);
    1677                 :            :         uint32_t c1 = ((uint32_t)it->bytes[it->i]) | (((uint32_t)it->bytes[it->i + 1]) << 8);
    1678                 :            :         assert((c1 & ~((uint32_t)0x03ff)) == 0xdc00);
    1679                 :            :         it->i += 2;
    1680                 :            :         return Optional<uint32_t>::some(0x10000 + (((c0 & 0x03ff) << 10) | (c1 & 0x03ff)));
    1681                 :            :     } else {
    1682                 :            :         assert((c0 & ~((uint32_t)0x03ff)) != 0xdc00);
    1683                 :            :         it->i += 2;
    1684                 :            :         return Optional<uint32_t>::some(c0);
    1685                 :            :     }
    1686                 :            : }
    1687                 :            : 
    1688                 :            : // Ported from std/unicode.zig
    1689                 :            : static uint8_t utf8CodepointSequenceLength(uint32_t c) {
    1690                 :            :     if (c < 0x80) return 1;
    1691                 :            :     if (c < 0x800) return 2;
    1692                 :            :     if (c < 0x10000) return 3;
    1693                 :            :     if (c < 0x110000) return 4;
    1694                 :            :     zig_unreachable();
    1695                 :            : }
    1696                 :            : 
    1697                 :            : // Ported from std/unicode.zig
    1698                 :            : static size_t utf8Encode(uint32_t c, Slice<uint8_t> out) {
    1699                 :            :     size_t length = utf8CodepointSequenceLength(c);
    1700                 :            :     assert(out.len >= length);
    1701                 :            :     switch (length) {
    1702                 :            :         // The pattern for each is the same
    1703                 :            :         // - Increasing the initial shift by 6 each time
    1704                 :            :         // - Each time after the first shorten the shifted
    1705                 :            :         //   value to a max of 0b111111 (63)
    1706                 :            :         case 1:
    1707                 :            :             out.ptr[0] = c; // Can just do 0 + codepoint for initial range
    1708                 :            :             break;
    1709                 :            :         case 2:
    1710                 :            :             out.ptr[0] = 0b11000000 | (c >> 6);
    1711                 :            :             out.ptr[1] = 0b10000000 | (c & 0b111111);
    1712                 :            :             break;
    1713                 :            :         case 3:
    1714                 :            :             assert(!(0xd800 <= c && c <= 0xdfff));
    1715                 :            :             out.ptr[0] = 0b11100000 | (c >> 12);
    1716                 :            :             out.ptr[1] = 0b10000000 | ((c >> 6) & 0b111111);
    1717                 :            :             out.ptr[2] = 0b10000000 | (c & 0b111111);
    1718                 :            :             break;
    1719                 :            :         case 4:
    1720                 :            :             out.ptr[0] = 0b11110000 | (c >> 18);
    1721                 :            :             out.ptr[1] = 0b10000000 | ((c >> 12) & 0b111111);
    1722                 :            :             out.ptr[2] = 0b10000000 | ((c >> 6) & 0b111111);
    1723                 :            :             out.ptr[3] = 0b10000000 | (c & 0b111111);
    1724                 :            :             break;
    1725                 :            :         default:
    1726                 :            :             zig_unreachable();
    1727                 :            :     }
    1728                 :            :     return length;
    1729                 :            : }
    1730                 :            : 
    1731                 :            : // Ported from std.unicode.utf16leToUtf8Alloc
    1732                 :            : static void utf16le_ptr_to_utf8(Buf *out, WCHAR *utf16le) {
    1733                 :            :     // optimistically guess that it will all be ascii.
    1734                 :            :     buf_resize(out, 0);
    1735                 :            :     size_t out_index = 0;
    1736                 :            :     Utf16LeIterator it = Utf16LeIterator_init(utf16le);
    1737                 :            :     for (;;) {
    1738                 :            :         Optional<uint32_t> opt_codepoint = Utf16LeIterator_nextCodepoint(&it);
    1739                 :            :         if (!opt_codepoint.is_some) break;
    1740                 :            :         uint32_t codepoint = opt_codepoint.value;
    1741                 :            : 
    1742                 :            :         size_t utf8_len = utf8CodepointSequenceLength(codepoint);
    1743                 :            :         buf_resize(out, buf_len(out) + utf8_len);
    1744                 :            :         utf8Encode(codepoint, {(uint8_t*)buf_ptr(out)+out_index, buf_len(out)-out_index});
    1745                 :            :         out_index += utf8_len;
    1746                 :            :     }
    1747                 :            : }
    1748                 :            : #endif
    1749                 :            : 
    1750                 :            : // Ported from std.os.getAppDataDir
    1751                 :         18 : Error os_get_app_data_dir(Buf *out_path, const char *appname) {
    1752                 :            : #if defined(ZIG_OS_WINDOWS)
    1753                 :            :     WCHAR *dir_path_ptr;
    1754                 :            :     switch (SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &dir_path_ptr)) {
    1755                 :            :         case S_OK:
    1756                 :            :             // defer os.windows.CoTaskMemFree(@ptrCast(*c_void, dir_path_ptr));
    1757                 :            :             utf16le_ptr_to_utf8(out_path, dir_path_ptr);
    1758                 :            :             CoTaskMemFree(dir_path_ptr);
    1759                 :            :             buf_appendf(out_path, "\\%s", appname);
    1760                 :            :             return ErrorNone;
    1761                 :            :         case E_OUTOFMEMORY:
    1762                 :            :             return ErrorNoMem;
    1763                 :            :         default:
    1764                 :            :             return ErrorUnexpected;
    1765                 :            :     }
    1766                 :            :     zig_unreachable();
    1767                 :            : #elif defined(ZIG_OS_DARWIN)
    1768                 :            :     const char *home_dir = getenv("HOME");
    1769                 :            :     if (home_dir == nullptr) {
    1770                 :            :         // TODO use /etc/passwd
    1771                 :            :         return ErrorFileNotFound;
    1772                 :            :     }
    1773                 :            :     buf_resize(out_path, 0);
    1774                 :            :     buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname);
    1775                 :            :     return ErrorNone;
    1776                 :            : #elif defined(ZIG_OS_POSIX)
    1777                 :         18 :     const char *home_dir = getenv("HOME");
    1778         [ -  + ]:         18 :     if (home_dir == nullptr) {
    1779                 :            :         // TODO use /etc/passwd
    1780                 :          0 :         return ErrorFileNotFound;
    1781                 :            :     }
    1782         [ -  + ]:         18 :     if (home_dir[0] == 0) {
    1783                 :          0 :         return ErrorFileNotFound;
    1784                 :            :     }
    1785                 :         18 :     buf_init_from_str(out_path, home_dir);
    1786         [ +  - ]:         18 :     if (buf_ptr(out_path)[buf_len(out_path) - 1] != '/') {
    1787                 :         18 :         buf_append_char(out_path, '/');
    1788                 :            :     }
    1789                 :         18 :     buf_appendf(out_path, ".local/share/%s", appname);
    1790                 :         18 :     return ErrorNone;
    1791                 :            : #endif
    1792                 :            : }
    1793                 :            : 
    1794                 :            : 
    1795                 :            : #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
    1796                 :        230 : static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
    1797                 :        230 :     ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
    1798         [ +  + ]:        230 :     if (info->dlpi_name[0] == '/') {
    1799                 :        184 :         libs->append(buf_create_from_str(info->dlpi_name));
    1800                 :            :     }
    1801                 :        230 :     return 0;
    1802                 :            : }
    1803                 :            : #endif
    1804                 :            : 
    1805                 :         23 : Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
    1806                 :            : #if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD) || defined(ZIG_OS_NETBSD)
    1807                 :         23 :     paths.resize(0);
    1808                 :         23 :     dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
    1809                 :         23 :     return ErrorNone;
    1810                 :            : #elif defined(ZIG_OS_DARWIN)
    1811                 :            :     paths.resize(0);
    1812                 :            :     uint32_t img_count = _dyld_image_count();
    1813                 :            :     for (uint32_t i = 0; i != img_count; i += 1) {
    1814                 :            :         const char *name = _dyld_get_image_name(i);
    1815                 :            :         paths.append(buf_create_from_str(name));
    1816                 :            :     }
    1817                 :            :     return ErrorNone;
    1818                 :            : #elif defined(ZIG_OS_WINDOWS)
    1819                 :            :     // zig is built statically on windows, so we can return an empty list
    1820                 :            :     paths.resize(0);
    1821                 :            :     return ErrorNone;
    1822                 :            : #else
    1823                 :            : #error unimplemented
    1824                 :            : #endif
    1825                 :            : }
    1826                 :            : 
    1827                 :       5454 : Error os_file_open_r(Buf *full_path, OsFile *out_file, OsFileAttr *attr) {
    1828                 :            : #if defined(ZIG_OS_WINDOWS)
    1829                 :            :     // TODO use CreateFileW
    1830                 :            :     HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
    1831                 :            : 
    1832                 :            :     if (result == INVALID_HANDLE_VALUE) {
    1833                 :            :         DWORD err = GetLastError();
    1834                 :            :         switch (err) {
    1835                 :            :             case ERROR_SHARING_VIOLATION:
    1836                 :            :                 return ErrorSharingViolation;
    1837                 :            :             case ERROR_ALREADY_EXISTS:
    1838                 :            :                 return ErrorPathAlreadyExists;
    1839                 :            :             case ERROR_FILE_EXISTS:
    1840                 :            :                 return ErrorPathAlreadyExists;
    1841                 :            :             case ERROR_FILE_NOT_FOUND:
    1842                 :            :                 return ErrorFileNotFound;
    1843                 :            :             case ERROR_PATH_NOT_FOUND:
    1844                 :            :                 return ErrorFileNotFound;
    1845                 :            :             case ERROR_ACCESS_DENIED:
    1846                 :            :                 return ErrorAccess;
    1847                 :            :             case ERROR_PIPE_BUSY:
    1848                 :            :                 return ErrorPipeBusy;
    1849                 :            :             default:
    1850                 :            :                 return ErrorUnexpected;
    1851                 :            :         }
    1852                 :            :     }
    1853                 :            :     *out_file = result;
    1854                 :            : 
    1855                 :            :     if (attr != nullptr) {
    1856                 :            :         BY_HANDLE_FILE_INFORMATION file_info;
    1857                 :            :         if (!GetFileInformationByHandle(result, &file_info)) {
    1858                 :            :             CloseHandle(result);
    1859                 :            :             return ErrorUnexpected;
    1860                 :            :         }
    1861                 :            :         windows_filetime_to_os_timestamp(&file_info.ftLastWriteTime, &attr->mtime);
    1862                 :            :         attr->inode = (((uint64_t)file_info.nFileIndexHigh) << 32) | file_info.nFileIndexLow;
    1863                 :            :     }
    1864                 :            : 
    1865                 :            :     return ErrorNone;
    1866                 :            : #else
    1867                 :            :     for (;;) {
    1868                 :       5454 :         int fd = open(buf_ptr(full_path), O_RDONLY|O_CLOEXEC);
    1869         [ -  + ]:       5454 :         if (fd == -1) {
    1870   [ #  #  #  #  :          0 :             switch (errno) {
                #  #  # ]
    1871                 :          0 :                 case EINTR:
    1872                 :          0 :                     continue;
    1873                 :          0 :                 case EINVAL:
    1874                 :          0 :                     zig_unreachable();
    1875                 :          0 :                 case EFAULT:
    1876                 :          0 :                     zig_unreachable();
    1877                 :          0 :                 case EACCES:
    1878                 :       5454 :                     return ErrorAccess;
    1879                 :          0 :                 case EISDIR:
    1880                 :          0 :                     return ErrorIsDir;
    1881                 :          0 :                 case ENOENT:
    1882                 :          0 :                     return ErrorFileNotFound;
    1883                 :          0 :                 default:
    1884                 :          0 :                     return ErrorFileSystem;
    1885                 :            :             }
    1886                 :            :         }
    1887                 :            :         struct stat statbuf;
    1888         [ -  + ]:       5454 :         if (fstat(fd, &statbuf) == -1) {
    1889                 :          0 :             close(fd);
    1890                 :          0 :             return ErrorFileSystem;
    1891                 :            :         }
    1892         [ -  + ]:       5454 :         if (S_ISDIR(statbuf.st_mode)) {
    1893                 :          0 :             close(fd);
    1894                 :          0 :             return ErrorIsDir;
    1895                 :            :         }
    1896                 :       5454 :         *out_file = fd;
    1897                 :            : 
    1898         [ +  - ]:       5454 :         if (attr != nullptr) {
    1899                 :       5454 :             attr->inode = statbuf.st_ino;
    1900                 :            : #if defined(ZIG_OS_DARWIN)
    1901                 :            :             attr->mtime.sec = statbuf.st_mtimespec.tv_sec;
    1902                 :            :             attr->mtime.nsec = statbuf.st_mtimespec.tv_nsec;
    1903                 :            : #else
    1904                 :       5454 :             attr->mtime.sec = statbuf.st_mtim.tv_sec;
    1905                 :       5454 :             attr->mtime.nsec = statbuf.st_mtim.tv_nsec;
    1906                 :            : #endif
    1907                 :            :         }
    1908                 :       5454 :         return ErrorNone;
    1909                 :          0 :     }
    1910                 :            : #endif
    1911                 :            : }
    1912                 :            : 
    1913                 :        148 : Error os_file_open_lock_rw(Buf *full_path, OsFile *out_file) {
    1914                 :            : #if defined(ZIG_OS_WINDOWS)
    1915                 :            :     for (;;) {
    1916                 :            :         HANDLE result = CreateFileA(buf_ptr(full_path), GENERIC_READ | GENERIC_WRITE,
    1917                 :            :             0, nullptr, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
    1918                 :            : 
    1919                 :            :         if (result == INVALID_HANDLE_VALUE) {
    1920                 :            :             DWORD err = GetLastError();
    1921                 :            :             switch (err) {
    1922                 :            :                 case ERROR_SHARING_VIOLATION:
    1923                 :            :                     // TODO wait for the lock instead of sleeping
    1924                 :            :                     Sleep(10);
    1925                 :            :                     continue;
    1926                 :            :                 case ERROR_ALREADY_EXISTS:
    1927                 :            :                     return ErrorPathAlreadyExists;
    1928                 :            :                 case ERROR_FILE_EXISTS:
    1929                 :            :                     return ErrorPathAlreadyExists;
    1930                 :            :                 case ERROR_FILE_NOT_FOUND:
    1931                 :            :                     return ErrorFileNotFound;
    1932                 :            :                 case ERROR_PATH_NOT_FOUND:
    1933                 :            :                     return ErrorFileNotFound;
    1934                 :            :                 case ERROR_ACCESS_DENIED:
    1935                 :            :                     return ErrorAccess;
    1936                 :            :                 case ERROR_PIPE_BUSY:
    1937                 :            :                     return ErrorPipeBusy;
    1938                 :            :                 default:
    1939                 :            :                     return ErrorUnexpected;
    1940                 :            :             }
    1941                 :            :         }
    1942                 :            :         *out_file = result;
    1943                 :            :         return ErrorNone;
    1944                 :            :     }
    1945                 :            : #else
    1946                 :            :     int fd;
    1947                 :            :     for (;;) {
    1948                 :        148 :         fd = open(buf_ptr(full_path), O_RDWR|O_CLOEXEC|O_CREAT, 0666);
    1949         [ -  + ]:        148 :         if (fd == -1) {
    1950   [ #  #  #  #  :          0 :             switch (errno) {
             #  #  #  # ]
    1951                 :          0 :                 case EINTR:
    1952                 :          0 :                     continue;
    1953                 :          0 :                 case EINVAL:
    1954                 :          0 :                     zig_unreachable();
    1955                 :          0 :                 case EFAULT:
    1956                 :          0 :                     zig_unreachable();
    1957                 :          0 :                 case EACCES:
    1958                 :          0 :                     return ErrorAccess;
    1959                 :          0 :                 case EISDIR:
    1960                 :          0 :                     return ErrorIsDir;
    1961                 :          0 :                 case ENOENT:
    1962                 :          0 :                     return ErrorFileNotFound;
    1963                 :          0 :                 case ENOTDIR:
    1964                 :          0 :                     return ErrorNotDir;
    1965                 :          0 :                 default:
    1966                 :          0 :                     return ErrorFileSystem;
    1967                 :            :             }
    1968                 :            :         }
    1969                 :        148 :         break;
    1970                 :            :     }
    1971                 :            :     for (;;) {
    1972                 :            :         struct flock lock;
    1973                 :        148 :         lock.l_type = F_WRLCK;
    1974                 :        148 :         lock.l_whence = SEEK_SET;
    1975                 :        148 :         lock.l_start = 0;
    1976                 :        148 :         lock.l_len = 0;
    1977         [ -  + ]:        148 :         if (fcntl(fd, F_SETLKW, &lock) == -1) {
    1978   [ #  #  #  #  :          0 :             switch (errno) {
                      # ]
    1979                 :          0 :                 case EINTR:
    1980                 :          0 :                     continue;
    1981                 :          0 :                 case EBADF:
    1982                 :          0 :                     zig_unreachable();
    1983                 :          0 :                 case EFAULT:
    1984                 :          0 :                     zig_unreachable();
    1985                 :          0 :                 case EINVAL:
    1986                 :          0 :                     zig_unreachable();
    1987                 :          0 :                 default:
    1988                 :          0 :                     close(fd);
    1989                 :          0 :                     return ErrorFileSystem;
    1990                 :            :             }
    1991                 :            :         }
    1992                 :        148 :         break;
    1993                 :          0 :     }
    1994                 :        148 :     *out_file = fd;
    1995                 :        148 :     return ErrorNone;
    1996                 :            : #endif
    1997                 :            : }
    1998                 :            : 
    1999                 :      65385 : Error os_file_read(OsFile file, void *ptr, size_t *len) {
    2000                 :            : #if defined(ZIG_OS_WINDOWS)
    2001                 :            :     DWORD amt_read;
    2002                 :            :     if (ReadFile(file, ptr, *len, &amt_read, nullptr) == 0)
    2003                 :            :         return ErrorUnexpected;
    2004                 :            :     *len = amt_read;
    2005                 :            :     return ErrorNone;
    2006                 :            : #else
    2007                 :            :     for (;;) {
    2008                 :      65385 :         ssize_t rc = read(file, ptr, *len);
    2009         [ -  + ]:      65385 :         if (rc == -1) {
    2010   [ #  #  #  #  :          0 :             switch (errno) {
                      # ]
    2011                 :          0 :                 case EINTR:
    2012                 :          0 :                     continue;
    2013                 :          0 :                 case EBADF:
    2014                 :          0 :                     zig_unreachable();
    2015                 :          0 :                 case EFAULT:
    2016                 :          0 :                     zig_unreachable();
    2017                 :          0 :                 case EISDIR:
    2018                 :          0 :                     return ErrorIsDir;
    2019                 :          0 :                 default:
    2020                 :          0 :                     return ErrorFileSystem;
    2021                 :            :             }
    2022                 :            :         }
    2023                 :      65385 :         *len = rc;
    2024                 :      65385 :         return ErrorNone;
    2025                 :          0 :     }
    2026                 :            : #endif
    2027                 :            : }
    2028                 :            : 
    2029                 :        148 : Error os_file_read_all(OsFile file, Buf *contents) {
    2030                 :            :     Error err;
    2031                 :        148 :     size_t index = 0;
    2032                 :            :     for (;;) {
    2033                 :        296 :         size_t amt = buf_len(contents) - index;
    2034                 :            : 
    2035         [ +  - ]:        296 :         if (amt < 4096) {
    2036                 :        296 :             buf_resize(contents, buf_len(contents) + (4096 - amt));
    2037                 :        296 :             amt = buf_len(contents) - index;
    2038                 :            :         }
    2039                 :            : 
    2040         [ -  + ]:        296 :         if ((err = os_file_read(file, buf_ptr(contents) + index, &amt)))
    2041                 :        148 :             return err;
    2042                 :            : 
    2043         [ +  + ]:        296 :         if (amt == 0) {
    2044                 :        148 :             buf_resize(contents, index);
    2045                 :        148 :             return ErrorNone;
    2046                 :            :         }
    2047                 :            : 
    2048                 :        148 :         index += amt;
    2049                 :        148 :     }
    2050                 :            : }
    2051                 :            : 
    2052                 :         74 : Error os_file_overwrite(OsFile file, Buf *contents) {
    2053                 :            : #if defined(ZIG_OS_WINDOWS)
    2054                 :            :     if (SetFilePointer(file, 0, nullptr, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
    2055                 :            :         return ErrorFileSystem;
    2056                 :            :     if (!SetEndOfFile(file))
    2057                 :            :         return ErrorFileSystem;
    2058                 :            :     DWORD bytes_written;
    2059                 :            :     if (!WriteFile(file, buf_ptr(contents), buf_len(contents), &bytes_written, nullptr))
    2060                 :            :         return ErrorFileSystem;
    2061                 :            :     return ErrorNone;
    2062                 :            : #else
    2063         [ -  + ]:         74 :     if (lseek(file, 0, SEEK_SET) == -1)
    2064                 :          0 :         return ErrorUnexpectedSeekFailure;
    2065         [ -  + ]:         74 :     if (ftruncate(file, 0) == -1)
    2066                 :          0 :         return ErrorUnexpectedFileTruncationFailure;
    2067                 :            :     for (;;) {
    2068         [ -  + ]:         74 :         if (write(file, buf_ptr(contents), buf_len(contents)) == -1) {
    2069   [ #  #  #  #  :          0 :             switch (errno) {
          #  #  #  #  #  
                      # ]
    2070                 :          0 :                 case EINTR:
    2071                 :          0 :                     continue;
    2072                 :          0 :                 case EINVAL:
    2073                 :          0 :                     zig_unreachable();
    2074                 :          0 :                 case EBADF:
    2075                 :          0 :                     zig_unreachable();
    2076                 :          0 :                 case EFAULT:
    2077                 :          0 :                     zig_unreachable();
    2078                 :          0 :                 case EDQUOT:
    2079                 :          0 :                     return ErrorDiskQuota;
    2080                 :          0 :                 case ENOSPC:
    2081                 :          0 :                     return ErrorDiskSpace;
    2082                 :          0 :                 case EFBIG:
    2083                 :          0 :                     return ErrorFileTooBig;
    2084                 :          0 :                 case EIO:
    2085                 :          0 :                     return ErrorFileSystem;
    2086                 :          0 :                 case EPERM:
    2087                 :          0 :                     return ErrorAccess;
    2088                 :          0 :                 default:
    2089                 :          0 :                     return ErrorUnexpectedWriteFailure;
    2090                 :            :             }
    2091                 :            :         }
    2092                 :         74 :         return ErrorNone;
    2093                 :            :     }
    2094                 :            : #endif
    2095                 :            : }
    2096                 :            : 
    2097                 :       5602 : void os_file_close(OsFile *file) {
    2098                 :            : #if defined(ZIG_OS_WINDOWS)
    2099                 :            :     CloseHandle(*file);
    2100                 :            :     *file = NULL;
    2101                 :            : #else
    2102                 :       5602 :     close(*file);
    2103                 :       5602 :     *file = -1;
    2104                 :            : #endif
    2105                 :       5602 : }
    2106                 :            : 
    2107                 :            : #ifdef ZIG_OS_LINUX
    2108                 :            : const char *possible_ld_names[] = {
    2109                 :            : #if defined(ZIG_ARCH_X86_64)
    2110                 :            :     "ld-linux-x86-64.so.2",
    2111                 :            :     "ld-musl-x86_64.so.1",
    2112                 :            : #elif defined(ZIG_ARCH_ARM64)
    2113                 :            :     "ld-linux-aarch64.so.1",
    2114                 :            :     "ld-musl-aarch64.so.1",
    2115                 :            : #elif defined(ZIG_ARCH_ARM)
    2116                 :            :     "ld-linux-armhf.so.3",
    2117                 :            :     "ld-musl-armhf.so.1",
    2118                 :            :     "ld-linux.so.3",
    2119                 :            :     "ld-musl-arm.so.1",
    2120                 :            : #endif
    2121                 :            :     NULL,
    2122                 :            : };
    2123                 :            : #endif

Generated by: LCOV version 1.14