Index: /trunk/src/kash/shfile.c
===================================================================
--- /trunk/src/kash/shfile.c	(revision 2302)
+++ /trunk/src/kash/shfile.c	(revision 2303)
@@ -73,4 +73,16 @@
         return (rc); \
     } while (0)
+
+#if K_OS == K_OS_WINDOWS
+ /* See msdos.h for description. */
+# define FOPEN              0x01
+# define FEOFLAG            0x02
+# define FCRLF              0x04
+# define FPIPE              0x08
+# define FNOINHERIT         0x10
+# define FAPPEND            0x20
+# define FDEV               0x40
+# define FTEXT              0x80
+#endif
 
 
@@ -448,5 +460,6 @@
 }
 
-#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE) //&& defined(SH_FORKED_MODE)
+#if K_OS == K_OS_WINDOWS && defined(SHFILE_IN_USE)
+
 /**
  * Helper for shfork.
@@ -461,4 +474,5 @@
     shmtxtmp tmp;
     unsigned i;
+    DWORD fFlag = set ? HANDLE_FLAG_INHERIT : 0;
 
     shmtx_enter(&pfdtab->mtx, &tmp);
@@ -471,10 +485,7 @@
         {
             HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
-            DWORD  fFlag = (set || !pfdtab->tab[i].cloexec)
-                         ? HANDLE_FLAG_INHERIT : 0;
             if (set)
-                TRACE2((NULL, "  #%d: native=%#x flags=%#x cloexec=%d fFlag=%#x\n",
-                        i, pfdtab->tab[i].flags, hFile, pfdtab->tab[i].cloexec, fFlag));
-
+                TRACE2((NULL, "  #%d: native=%#x flags=%#x cloexec=%d\n",
+                        i, pfdtab->tab[i].flags, hFile, pfdtab->tab[i].cloexec));
             if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, fFlag))
             {
@@ -499,5 +510,109 @@
     shmtx_leave(&pfdtab->mtx, &tmp);
 }
-#endif
+
+/**
+ * Helper for sh_execve.
+ *
+ * This is called before and after CreateProcess. On the first call it
+ * will mark the non-close-on-exec handles as inheritable and produce
+ * the startup info for the CRT. On the second call, after CreateProcess,
+ * it will restore the handle inheritability properties.
+ *
+ * @returns Pointer to CRT data if prepare is 1, NULL if prepare is 0.
+ * @param   pfdtab  The file descriptor table.
+ * @param   prepare Which call, 1 if before and 0 if after.
+ * @param   sizep   Where to store the size of the returned data.
+ * @param   hndls   Where to store the three standard handles.
+ */
+void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls)
+{
+    void       *pvRet;
+    shmtxtmp    tmp;
+    unsigned    count;
+    unsigned    i;
+
+    shmtx_enter(&pfdtab->mtx, &tmp);
+    TRACE2((NULL, "shfile_fork_win:\n"));
+
+    count  = pfdtab->size < (0x10000-4) / (1 + sizeof(HANDLE))
+           ? pfdtab->size
+           : (0x10000-4) / (1 + sizeof(HANDLE));
+
+    if (prepare)
+    {
+        size_t      cbData = sizeof(int) + count * (1 + sizeof(HANDLE));
+        uint8_t    *pbData = sh_malloc(shthread_get_shell(), cbData);
+        uint8_t    *paf = pbData + sizeof(int);
+        HANDLE     *pah = (HANDLE *)(paf + count);
+
+        *(int *)pbData = count;
+
+        i = count;
+        while (i-- > 0)
+        {
+            if (    pfdtab->tab[i].fd == i
+                &&  !pfdtab->tab[i].cloexec)
+            {
+                HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
+                TRACE2((NULL, "  #%d: native=%#x flags=%#x\n",
+                        i, pfdtab->tab[i].flags, hFile));
+
+                if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
+                {
+                    DWORD err = GetLastError();
+                    assert(0);
+                }
+                paf[i] = FOPEN;
+                if (pfdtab->tab[i].flags & _O_APPEND)
+                    paf[i] = FAPPEND;
+                if (pfdtab->tab[i].flags & _O_TEXT)
+                    paf[i] = FTEXT;
+                pah[i] = hFile;
+            }
+            else
+            {
+                paf[i] = 0;
+                pah[i] = INVALID_HANDLE_VALUE;
+            }
+        }
+
+        for (i = 0; i < 3; i++)
+        {
+            if (    count > i
+                &&  pfdtab->tab[i].fd == 0)
+                hndls[i] = pfdtab->tab[i].native;
+            else
+                hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
+        }
+
+        *sizep = (unsigned short)cbData;
+        pvRet = pbData;
+    }
+    else
+    {
+        assert(!hndls);
+        assert(!sizep);
+        i = count;
+        while (i-- > 0)
+        {
+            if (    pfdtab->tab[i].fd == i
+                &&  !pfdtab->tab[i].cloexec)
+            {
+                HANDLE hFile = (HANDLE)pfdtab->tab[i].native;
+                if (!SetHandleInformation(hFile, HANDLE_FLAG_INHERIT, 0))
+                {
+                    DWORD err = GetLastError();
+                    assert(0);
+                }
+            }
+        }
+        pvRet = NULL;
+    }
+
+    shmtx_leave(&pfdtab->mtx, &tmp);
+    return pvRet;
+}
+
+#endif /* K_OS_WINDOWS */
 
 
@@ -538,5 +653,5 @@
     SecurityAttributes.nLength = sizeof(SecurityAttributes);
     SecurityAttributes.lpSecurityDescriptor = NULL;
-    SecurityAttributes.bInheritHandle = (flags & _O_NOINHERIT) == 0;
+    SecurityAttributes.bInheritHandle = FALSE;
 
     if (flags & _O_CREAT)
@@ -599,5 +714,5 @@
 # endif /* K_OS != K_OS_WINDOWS */
 
-#elif defined(SH_FORKED_MODE)
+#else
     fd = open(name, flags, mode);
 #endif
@@ -619,5 +734,5 @@
     SecurityAttributes.nLength = sizeof(SecurityAttributes);
     SecurityAttributes.lpSecurityDescriptor = NULL;
-    SecurityAttributes.bInheritHandle = TRUE;
+    SecurityAttributes.bInheritHandle = FALSE;
 
     fds[1] = fds[0] = -1;
@@ -680,5 +795,5 @@
     }
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = pipe(fds);
 #endif
@@ -688,15 +803,10 @@
 }
 
+/**
+ * dup().
+ */
 int shfile_dup(shfdtab *pfdtab, int fd)
 {
-    int rc;
-#if defined(SH_FORKED_MODE)
-    rc = dup(fd);
-
-#else
-#endif
-
-    TRACE2((NULL, "shfile_dup(%d) -> %d [%d]\n", fd, rc, errno));
-    return rc;
+    return shfile_fcntl(pfdtab,fd, F_DUPFD, 0);
 }
 
@@ -724,5 +834,5 @@
         rc = -1;
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = close(fd);
 #endif
@@ -758,5 +868,5 @@
         rc = -1;
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = read(fd, buf, len);
 #endif
@@ -790,5 +900,5 @@
         rc = -1;
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = write(fd, buf, len);
 #endif
@@ -823,5 +933,5 @@
         rc = -1;
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = lseek(fd, off, whench);
 #endif
@@ -882,5 +992,5 @@
                                     &hNew,
                                     0,
-                                    TRUE /* bInheritHandle */,
+                                    FALSE /* bInheritHandle */,
                                     DUPLICATE_SAME_ACCESS))
                     rc = shfile_insert(pfdtab, (intptr_t)hNew, file->flags, arg, "shfile_fcntl");
@@ -906,5 +1016,5 @@
         rc = -1;
 
-#elif defined(SH_FORKED_MODE)
+#else
     rc = fcntl(fd, cmd, arg);
 #endif
@@ -922,49 +1032,129 @@
 int shfile_stat(shfdtab *pfdtab, const char *path, struct stat *pst)
 {
-#if defined(SH_FORKED_MODE)
+#ifdef SHFILE_IN_USE
+    char    abspath[SHFILE_MAX_PATH];
+    int     rc;
+    rc = shfile_make_path(pfdtab, path, &abspath[0]);
+    if (!rc)
+    {
+# if K_OS == K_OS_WINDOWS
+        rc = stat(abspath, pst); /** @todo re-implement stat. */
+# else
+        rc = stat(abspath, pst);
+# endif
+    }
+    TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno));
+    return rc;
+#else
     return stat(path, pst);
-
-#else
-#endif
-}
-
-int shfile_lstat(shfdtab *pfdtab, const char *link, struct stat *pst)
-{
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
-    return stat(link, pst);
+#endif
+}
+
+int shfile_lstat(shfdtab *pfdtab, const char *path, struct stat *pst)
+{
+    int     rc;
+#ifdef SHFILE_IN_USE
+    char    abspath[SHFILE_MAX_PATH];
+
+    rc = shfile_make_path(pfdtab, path, &abspath[0]);
+    if (!rc)
+    {
+# if K_OS == K_OS_WINDOWS
+        rc = stat(abspath, pst); /** @todo implement lstat. */
 # else
-    return lstat(link, pst);
-# endif
-
-#else
-#endif
-}
-
+        rc = lstat(abspath, pst);
+# endif
+    }
+#else
+    rc = stat(path, pst);
+#endif
+    TRACE2((NULL, "shfile_stat(,%s,) -> %d [%d]\n", path, rc, errno));
+    return rc;
+}
+
+/**
+ * chdir().
+ */
 int shfile_chdir(shfdtab *pfdtab, const char *path)
 {
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER //???
-    return chdir(path);
-# else
-    return chdir(path);
-# endif
-
-#else
-#endif
-}
-
-char *shfile_getcwd(shfdtab *pfdtab, char *buf, int len)
-{
-#if defined(SH_FORKED_MODE)
-    return getcwd(buf, len);
-
-#else
-#endif
+    shinstance *psh = shthread_get_shell();
+    int         rc;
+#ifdef SHFILE_IN_USE
+    char        abspath[SHFILE_MAX_PATH];
+
+    rc = shfile_make_path(pfdtab, path, &abspath[0]);
+    if (!rc)
+    {
+        char *abspath_copy = sh_strdup(psh, abspath);
+        char *free_me = abspath_copy;
+        rc = chdir(path);
+        if (!rc)
+        {
+            shmtxtmp    tmp;
+            shmtx_enter(&pfdtab->mtx, &tmp);
+
+            free_me = pfdtab->cwd;
+            pfdtab->cwd = abspath_copy;
+
+            shmtx_leave(&pfdtab->mtx, &tmp);
+        }
+        sh_free(psh, free_me);
+    }
+#else
+    rc = chdir(path);
+#endif
+
+    TRACE2((psh, "shfile_chdir(,%s) -> %d [%d]\n", path, rc, errno));
+    return rc;
+}
+
+/**
+ * getcwd().
+ */
+char *shfile_getcwd(shfdtab *pfdtab, char *buf, int size)
+{
+    char       *ret;
+#ifdef SHFILE_IN_USE
+
+    ret = NULL;
+    if (buf && !size)
+        errno = -EINVAL;
+    else
+    {
+        size_t      cwd_size;
+        shmtxtmp    tmp;
+        shmtx_enter(&pfdtab->mtx, &tmp);
+
+        cwd_size = strlen(pfdtab->cwd) + 1;
+        if (buf)
+        {
+            if (cwd_size <= (size_t)size)
+                ret = memcpy(buf, pfdtab->cwd, cwd_size);
+            else
+                errno = ERANGE;
+        }
+        else
+        {
+            if (size < cwd_size)
+                size = (int)cwd_size;
+            ret = sh_malloc(shthread_get_shell(), size);
+            if (ret)
+                ret = memcpy(ret, pfdtab->cwd, cwd_size);
+            else
+                errno = ENOMEM;
+        }
+
+        shmtx_leave(&pfdtab->mtx, &tmp);
+    }
+#else
+    ret = getcwd(buf, size);
+#endif
+
+    TRACE2((NULL, "shfile_getcwd(,%p,%d) -> %s [%d]\n", buf, size, ret, errno));
+    return ret;
 }
 
 int shfile_access(shfdtab *pfdtab, const char *path, int type)
 {
-#if defined(SH_FORKED_MODE)
 # ifdef _MSC_VER
     type &= ~X_OK;
@@ -973,16 +1163,28 @@
     return access(path, type);
 # endif
-
-#else
-#endif
-}
-
+}
+
+/**
+ * isatty()
+ */
 int shfile_isatty(shfdtab *pfdtab, int fd)
 {
-    int rc;
-
-#if defined(SH_FORKED_MODE)
+    int         rc;
+#ifdef SHFILE_IN_USE
+    shmtxtmp    tmp;
+    shfile     *file = shfile_get(pfdtab, fd, &tmp);
+    if (file)
+    {
+# if K_OS == K_OS_WINDOWS
+        errno = ENOSYS;
+# else
+        rc = isatty(file->native);
+# endif
+        shfile_put(pfdtab, file, &tmp);
+    }
+    else
+        rc = 0;
+#else
     rc = isatty(fd);
-#else
 #endif
 
@@ -991,19 +1193,23 @@
 }
 
-
+/**
+ * fcntl F_SETFD / FD_CLOEXEC.
+ */
 int shfile_cloexec(shfdtab *pfdtab, int fd, int closeit)
 {
-    int rc;
-
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
-    errno = ENOSYS;
-    rc = -1;
-# else
+    int         rc;
+#ifdef SHFILE_IN_USE
+    shmtxtmp    tmp;
+    shfile     *file = shfile_get(pfdtab, fd, &tmp);
+    if (file)
+    {
+        file->cloexec = !!(closeit);
+        shfile_put(pfdtab, file, &tmp);
+    }
+    else
+        rc = -1;
+#else
     rc = fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0)
                           | (closeit ? FD_CLOEXEC : 0));
-# endif
-
-#else
 #endif
 
@@ -1015,15 +1221,22 @@
 int shfile_ioctl(shfdtab *pfdtab, int fd, unsigned long request, void *buf)
 {
-    int rc;
-
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
-    errno = ENOSYS;
-    rc = -1;
+    int         rc;
+#ifdef SHFILE_IN_USE
+    shmtxtmp    tmp;
+    shfile     *file = shfile_get(pfdtab, fd, &tmp);
+    if (file)
+    {
+# if K_OS == K_OS_WINDOWS
+        rc = -1;
+        errno = ENOSYS;
 # else
+        rc = ioctl(file->native, request, buf);
+# endif
+        shfile_put(pfdtab, file, &tmp);
+    }
+    else
+        rc = -1;
+#else
     rc = ioctl(fd, request, buf);
-# endif
-
-#else
 #endif
 
@@ -1035,13 +1248,11 @@
 mode_t shfile_get_umask(shfdtab *pfdtab)
 {
-#if defined(SH_FORKED_MODE)
+    /** @todo */
     return 022;
-
-#else
-#endif
 }
 
 void shfile_set_umask(shfdtab *pfdtab, mode_t mask)
 {
+    /** @todo */
     (void)mask;
 }
@@ -1050,13 +1261,9 @@
 shdir *shfile_opendir(shfdtab *pfdtab, const char *dir)
 {
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
+#ifdef SHFILE_IN_USE
     errno = ENOSYS;
     return NULL;
-# else
+#else
     return (shdir *)opendir(dir);
-# endif
-
-#else
 #endif
 }
@@ -1064,14 +1271,10 @@
 shdirent *shfile_readdir(struct shdir *pdir)
 {
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
+#ifdef SHFILE_IN_USE
     errno = ENOSYS;
     return NULL;
-# else
+#else
     struct dirent *pde = readdir((DIR *)pdir);
     return pde ? (shdirent *)&pde->d_name[0] : NULL;
-# endif
-
-#else
 #endif
 }
@@ -1079,12 +1282,9 @@
 void shfile_closedir(struct shdir *pdir)
 {
-#if defined(SH_FORKED_MODE)
-# ifdef _MSC_VER
+#ifdef SHFILE_IN_USE
     errno = ENOSYS;
-# else
+#else
     closedir((DIR *)pdir);
-# endif
-
-#else
-#endif
-}
+#endif
+}
+
Index: /trunk/src/kash/shfile.h
===================================================================
--- /trunk/src/kash/shfile.h	(revision 2302)
+++ /trunk/src/kash/shfile.h	(revision 2303)
@@ -103,5 +103,5 @@
     int                 fd;             /**< The shell file descriptor number. */
     int                 flags;          /**< Open flags. */
-    int                 cloexec : 1;    /**< Close on exec flag. */
+    unsigned            cloexec : 1;    /**< Close on exec flag. */
     intptr_t            native;         /**< The native file descriptor number. */
 } shfile;
@@ -120,4 +120,5 @@
 int shfile_init(shfdtab *, shfdtab *);
 void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls);
+void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls);
 
 int shfile_open(shfdtab *, const char *, unsigned, mode_t);
Index: /trunk/src/kash/shinstance.c
===================================================================
--- /trunk/src/kash/shinstance.c	(revision 2302)
+++ /trunk/src/kash/shinstance.c	(revision 2303)
@@ -1055,9 +1055,5 @@
 int sh_execve(shinstance *psh, const char *exe, const char * const *argv, const char * const *envp)
 {
-#ifdef _MSC_VER
-    intptr_t rc;
-#else
     int rc;
-#endif
 
 #ifdef DEBUG
@@ -1071,14 +1067,19 @@
         envp = sh_environ(psh);
 
-#if defined(SH_FORKED_MODE)
+#if defined(SH_FORKED_MODE) && K_OS != K_OS_WINDOWS
+# ifdef _MSC_VER
     errno = 0;
-# ifdef _MSC_VER
-    errno = 0;
-    rc = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
-    if (rc != -1)
-    {
-        TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
-        exit((int)rc);
-    }
+    {
+        intptr_t rc2 = _spawnve(_P_WAIT, exe, (char **)argv, (char **)envp);
+        if (rc2 != -1)
+        {
+            TRACE2((psh, "sh_execve: child exited, rc=%d. (errno=%d)\n", rc, errno));
+            rc = (int)rc2;
+            if (!rc && rc2)
+                rc = 16;
+            exit(rc);
+        }
+    }
+    rc = -1;
 # else
     rc = execve(exe, (char **)argv, (char **)envp);
@@ -1086,4 +1087,100 @@
 
 #else
+# if K_OS == K_OS_WINDOWS
+    {
+        /*
+         * This ain't quite straight forward on Windows...
+         */
+        PROCESS_INFORMATION ProcInfo;
+        STARTUPINFO StrtInfo;
+        intptr_t hndls[3];
+        char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
+        char *cmdline;
+        size_t cmdline_size;
+        char *envblock;
+        size_t env_size;
+        char *p;
+        int i;
+
+        /* Create the environment block. */
+        if (!envp)
+            envp = sh_environ(psh);
+        env_size = 2;
+        for (i = 0; envp[i]; i++)
+            env_size += strlen(envp[i]) + 1;
+        envblock = p = sh_malloc(psh, env_size);
+        for (i = 0; envp[i]; i++)
+        {
+            size_t len = strlen(envp[i]) + 1;
+            memcpy(p, envp[i], len);
+            p += len;
+        }
+        *p = '\0';
+
+        /* Create the command line. */
+        cmdline_size = 2;
+        for (i = 0; argv[i]; i++)
+            cmdline_size += strlen(argv[i]) + 3;
+        cmdline = p = sh_malloc(psh, env_size);
+        for (i = 0; argv[i]; i++)
+        {
+            size_t len = strlen(argv[i]);
+            int quoted = !!strpbrk(argv[i], " \t"); /** @todo Do this quoting business right. */
+            if (i != 0)
+                *(p++) = ' ';
+            if (quoted)
+                *(p++) = '"';
+            memcpy(p, argv[i], len);
+            p += len;
+            if (quoted)
+                *(p++) = '"';
+        }
+        p[0] = p[1] = '\0';
+
+        /* Init the info structure */
+        memset(&StrtInfo, '\0', sizeof(StrtInfo));
+        StrtInfo.cb = sizeof(StrtInfo);
+
+        /* File handles. */
+        StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
+        StrtInfo.hStdInput  = (HANDLE)hndls[0];
+        StrtInfo.hStdOutput = (HANDLE)hndls[1];
+        StrtInfo.hStdError  = (HANDLE)hndls[2];
+
+        /* Get going... */
+        if (CreateProcess(exe,
+                          cmdline,
+                          NULL,         /* pProcessAttributes */
+                          NULL,         /* pThreadAttributes */
+                          TRUE,         /* bInheritHandles */
+                          0,            /* dwCreationFlags */
+                          envblock,
+                          cwd,
+                          &StrtInfo,
+                          &ProcInfo))
+        {
+            DWORD dwErr;
+            DWORD dwExitCode;
+
+            CloseHandle(ProcInfo.hThread);
+            dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
+            assert(dwErr == WAIT_OBJECT_0);
+
+            if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
+            {
+                CloseHandle(ProcInfo.hProcess);
+                _exit(dwExitCode);
+            }
+            errno = EINVAL;
+        }
+
+        shfile_exec_win(&psh->fdtab, 0 /* done */, NULL, NULL);
+    }
+    rc = -1;
+
+# else
+    errno = ENOSYS;
+    rc = -1;
+# endif
 #endif
 
