This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
I'm not convinced that manually creating HVs via sv_upgrade is a great
[perl5.git] / win32 / win32.c
index 633dbbd..40e28f5 100644 (file)
@@ -253,7 +253,8 @@ get_emd_part(SV **prev_pathp, char *trailing_path, ...)
        dTHX;
        if (!*prev_pathp)
            *prev_pathp = sv_2mortal(newSVpvn("",0));
-       sv_catpvn(*prev_pathp, ";", 1);
+       else if (SvPVX(*prev_pathp))
+           sv_catpvn(*prev_pathp, ";", 1);
        sv_catpv(*prev_pathp, mod_name);
        return SvPVX(*prev_pathp);
     }
@@ -506,7 +507,7 @@ get_shell(void)
         *     for).
         */
        const char* defaultshell = (IsWinNT()
-                                   ? "cmd.exe /x/c" : "command.com /c");
+                                   ? "cmd.exe /x/d/c" : "command.com /c");
        const char *usershell = PerlEnv_getenv("PERL5SHELL");
        w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
                                       &w32_perlshell_tokens,
@@ -1067,6 +1068,7 @@ win32_kill(int pid, int sig)
     dTHX;
     HANDLE hProcess;
     long child;
+    int retval;
 #ifdef USE_ITHREADS
     if (pid < 0) {
        /* it is a pseudo-forked child */
@@ -1114,6 +1116,11 @@ win32_kill(int pid, int sig)
                if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
                    return 0;
                break;
+            case SIGBREAK:
+            case SIGTERM:
+                if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
+                    return 0;
+                break;
            default: /* For now be backwards compatible with perl5.6 */
            case 9:
                if (TerminateProcess(hProcess, sig)) {
@@ -1125,25 +1132,34 @@ win32_kill(int pid, int sig)
        }
        else {
 alien_process:
+            retval = -1;
            hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE,
                                   (IsWin95() ? -pid : pid));
            if (hProcess) {
                switch(sig) {
                case 0:
                    /* "Does process exist?" use of kill */
-                   return 0;
+                   retval = 0;
+                    break;
                case 2:
                    if (GenerateConsoleCtrlEvent(CTRL_C_EVENT,pid))
-                       return 0;
+                       retval = 0;
                    break;
+                case SIGBREAK:
+                case SIGTERM:
+                    if (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT,pid))
+                       retval = 0;
+                    break;
                default: /* For now be backwards compatible with perl5.6 */
                 case 9:
-                   if (TerminateProcess(hProcess, sig)) {
-                       CloseHandle(hProcess);
-                       return 0;
-                   }
+                   if (TerminateProcess(hProcess, sig))
+                       retval = 0;
+                    break;
                }
            }
+            CloseHandle(hProcess);
+            if (retval == 0)
+                return 0;
        }
     }
     errno = EINVAL;
@@ -1167,6 +1183,10 @@ win32_stat(const char *path, Stat_t *sbuf)
        /* FindFirstFile() and stat() are buggy with a trailing
         * backslash, so change it to a forward slash :-( */
        case '\\':
+           if (l >= sizeof(buffer)) {
+               errno = ENAMETOOLONG;
+               return -1;
+           }
            strncpy(buffer, path, l-1);
            buffer[l - 1] = '/';
            buffer[l] = '\0';
@@ -1884,10 +1904,12 @@ win32_async_check(pTHX)
 
        case WM_TIMER: {
            /* alarm() is a one-shot but SetTimer() repeats so kill it */
-           if (w32_timerid) {
+           if (w32_timerid && w32_timerid==msg.wParam) {
                KillTimer(NULL,w32_timerid);
                w32_timerid=0;
            }
+            else
+               goto FallThrough;
            /* Now fake a call to signal handler */
            if (do_raise(aTHX_ 14)) {
                sig_terminate(aTHX_ 14);
@@ -1897,6 +1919,7 @@ win32_async_check(pTHX)
 
        /* Otherwise do normal Win32 thing - in case it is useful */
        default:
+       FallThrough:
            TranslateMessage(&msg);
            DispatchMessage(&msg);
            ours = 0;
@@ -1912,6 +1935,8 @@ win32_async_check(pTHX)
     return ours;
 }
 
+/* This function will not return until the timeout has elapsed, or until
+ * one of the handles is ready. */
 DllExport DWORD
 win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD resultp)
 {
@@ -1936,10 +1961,7 @@ win32_msgwait(pTHX_ DWORD count, LPHANDLE handles, DWORD timeout, LPDWORD result
         }
        if (result == WAIT_OBJECT_0 + count) {
            /* Message has arrived - check it */
-           if (win32_async_check(aTHX)) {
-               /* was one of ours */
-               break;
-           }
+           (void)win32_async_check(aTHX);
        }
        else {
           /* Not timeout or message - one of handles is ready */
@@ -2080,6 +2102,7 @@ alien_process:
            if (hProcess) {
                win32_msgwait(aTHX_ 1, &hProcess, timeout, &waitcode);
                if (waitcode == WAIT_TIMEOUT) {
+                    CloseHandle(hProcess);
                    return 0;
                }
                else if (waitcode == WAIT_OBJECT_0) {
@@ -2560,10 +2583,14 @@ DllExport Off_t
 win32_ftell(FILE *pf)
 {
 #if defined(WIN64) || defined(USE_LARGE_FILES)
+#if defined(__BORLAND__) /* buk */
+    return win32_tell( fileno( pf ) );
+#else
     fpos_t pos;
     if (fgetpos(pf, &pos))
        return -1;
     return (Off_t)pos;
+#endif
 #else
     return ftell(pf);
 #endif
@@ -2573,6 +2600,13 @@ DllExport int
 win32_fseek(FILE *pf, Off_t offset,int origin)
 {
 #if defined(WIN64) || defined(USE_LARGE_FILES)
+#if defined(__BORLANDC__) /* buk */
+    return win32_lseek(
+        fileno(pf),
+        offset,
+        origin
+        );
+#else
     fpos_t pos;
     switch (origin) {
     case SEEK_CUR:
@@ -2592,6 +2626,7 @@ win32_fseek(FILE *pf, Off_t offset,int origin)
        return -1;
     }
     return fsetpos(pf, &offset);
+#endif
 #else
     return fseek(pf, offset, origin);
 #endif
@@ -2600,13 +2635,25 @@ win32_fseek(FILE *pf, Off_t offset,int origin)
 DllExport int
 win32_fgetpos(FILE *pf,fpos_t *p)
 {
+#if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
+    if( win32_tell(fileno(pf)) == -1L ) {
+        errno = EBADF;
+        return -1;
+    }
+    return 0;
+#else
     return fgetpos(pf, p);
+#endif
 }
 
 DllExport int
 win32_fsetpos(FILE *pf,const fpos_t *p)
 {
+#if defined(__BORLANDC__) && defined(USE_LARGE_FILES) /* buk */
+    return win32_lseek(fileno(pf), *p, SEEK_CUR);
+#else
     return fsetpos(pf, p);
+#endif
 }
 
 DllExport void
@@ -2616,8 +2663,8 @@ win32_rewind(FILE *pf)
     return;
 }
 
-DllExport FILE*
-win32_tmpfile(void)
+DllExport int
+win32_tmpfd(void)
 {
     dTHX;
     char prefix[MAX_PATH+1];
@@ -2641,11 +2688,20 @@ win32_tmpfile(void)
 #endif
                    DEBUG_p(PerlIO_printf(Perl_debug_log,
                                          "Created tmpfile=%s\n",filename));
-                   return fdopen(fd, "w+b");
+                   return fd;
                }
            }
        }
     }
+    return -1;
+}
+
+DllExport FILE*
+win32_tmpfile(void)
+{
+    int fd = win32_tmpfd();
+    if (fd >= 0)
+       return win32_fdopen(fd, "w+b");
     return NULL;
 }
 
@@ -2750,6 +2806,12 @@ win32_popen(const char *command, const char *mode)
     if ((oldfd = win32_dup(stdfd)) == -1)
         goto cleanup;
 
+    /* save the old std handle (this needs to happen before the
+     * dup2(), since that might call SetStdHandle() too) */
+    OP_REFCNT_LOCK;
+    lock_held = 1;
+    old_h = GetStdHandle(nhandle);
+
     /* make stdfd go to child end of pipe (implicitly closes stdfd) */
     /* stdfd will be inherited by the child */
     if (win32_dup2(p[child], stdfd) == -1)
@@ -2758,10 +2820,7 @@ win32_popen(const char *command, const char *mode)
     /* close the child end in parent */
     win32_close(p[child]);
 
-    /* save the old std handle, and set the std handle */
-    OP_REFCNT_LOCK;
-    lock_held = 1;
-    old_h = GetStdHandle(nhandle);
+    /* set the new std handle (in case dup2() above didn't) */
     SetStdHandle(nhandle, (HANDLE)_get_osfhandle(stdfd));
 
     /* start the child */
@@ -2770,17 +2829,18 @@ win32_popen(const char *command, const char *mode)
        if ((childpid = do_spawn_nowait((char*)command)) == -1)
            goto cleanup;
 
-       /* restore the old std handle */
+       /* revert stdfd to whatever it was before */
+       if (win32_dup2(oldfd, stdfd) == -1)
+           goto cleanup;
+
+       /* restore the old std handle (this needs to happen after the
+        * dup2(), since that might call SetStdHandle() too */
        if (lock_held) {
            SetStdHandle(nhandle, old_h);
            OP_REFCNT_UNLOCK;
            lock_held = 0;
        }
 
-       /* revert stdfd to whatever it was before */
-       if (win32_dup2(oldfd, stdfd) == -1)
-           goto cleanup;
-
        /* close saved handle */
        win32_close(oldfd);
 
@@ -3073,11 +3133,76 @@ win32_setmode(int fd, int mode)
     return setmode(fd, mode);
 }
 
+DllExport int
+win32_chsize(int fd, Off_t size)
+{
+#if defined(WIN64) || defined(USE_LARGE_FILES)
+    int retval = 0;
+    Off_t cur, end, extend;
+
+    cur = win32_tell(fd);
+    if (cur < 0)
+       return -1;
+    end = win32_lseek(fd, 0, SEEK_END);
+    if (end < 0)
+       return -1;
+    extend = size - end;
+    if (extend == 0) {
+       /* do nothing */
+    }
+    else if (extend > 0) {
+       /* must grow the file, padding with nulls */
+       char b[4096];
+       int oldmode = win32_setmode(fd, O_BINARY);
+       size_t count;
+       memset(b, '\0', sizeof(b));
+       do {
+           count = extend >= sizeof(b) ? sizeof(b) : (size_t)extend;
+           count = win32_write(fd, b, count);
+           if ((int)count < 0) {
+               retval = -1;
+               break;
+           }
+       } while ((extend -= count) > 0);
+       win32_setmode(fd, oldmode);
+    }
+    else {
+       /* shrink the file */
+       win32_lseek(fd, size, SEEK_SET);
+       if (!SetEndOfFile((HANDLE)_get_osfhandle(fd))) {
+           errno = EACCES;
+           retval = -1;
+       }
+    }
+finish:
+    win32_lseek(fd, cur, SEEK_SET);
+    return retval;
+#else
+    return chsize(fd, size);
+#endif
+}
+
 DllExport Off_t
 win32_lseek(int fd, Off_t offset, int origin)
 {
 #if defined(WIN64) || defined(USE_LARGE_FILES)
+#if defined(__BORLANDC__) /* buk */
+    LARGE_INTEGER pos;
+    pos.QuadPart = offset;
+    pos.LowPart = SetFilePointer(
+        (HANDLE)_get_osfhandle(fd),
+        pos.LowPart,
+        &pos.HighPart,
+        origin
+    );
+    if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
+        pos.QuadPart = -1;
+    }
+
+    return pos.QuadPart;
+#else
     return _lseeki64(fd, offset, origin);
+#endif
 #else
     return lseek(fd, offset, origin);
 #endif
@@ -3087,7 +3212,24 @@ DllExport Off_t
 win32_tell(int fd)
 {
 #if defined(WIN64) || defined(USE_LARGE_FILES)
+#if defined(__BORLANDC__) /* buk */
+    LARGE_INTEGER pos;
+    pos.QuadPart = 0;
+    pos.LowPart = SetFilePointer(
+        (HANDLE)_get_osfhandle(fd),
+        pos.LowPart,
+        &pos.HighPart,
+        FILE_CURRENT
+    );
+    if (pos.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR) {
+        pos.QuadPart = -1;
+    }
+
+    return pos.QuadPart;
+    /* return tell(fd); */
+#else
     return _telli64(fd);
+#endif
 #else
     return tell(fd);
 #endif
@@ -3460,7 +3602,8 @@ create_command_line(char *cname, STRLEN clen, const char * const *args)
                || (IsWinNT() && stricmp(&cname[clen-4], ".cmd") == 0)))
        {
            bat_file = TRUE;
-           len += 3;
+           if (!IsWin95())
+               len += 3;
        }
        else {
            char *exe = strrchr(cname, '/');
@@ -3497,7 +3640,7 @@ create_command_line(char *cname, STRLEN clen, const char * const *args)
     New(1310, cmd, len, char);
     ptr = cmd;
 
-    if (bat_file) {
+    if (bat_file && !IsWin95()) {
        *ptr++ = '"';
        extra_quotes = TRUE;
     }
@@ -3547,7 +3690,9 @@ create_command_line(char *cname, STRLEN clen, const char * const *args)
 
        if (!extra_quotes
            && cmd_shell
-           && (stricmp(arg, "/x/c") == 0 || stricmp(arg, "/c") == 0))
+           && curlen >= 2
+           && *arg  == '/'     /* see if arg is "/c", "/x/c", "/x/d/c" etc. */
+           && stricmp(arg+curlen-2, "/c") == 0)
        {
            /* is there a next argument? */
            if (args[index+1]) {
@@ -3593,7 +3738,10 @@ qualified_path(const char *cmd)
 
     /* look in PATH */
     pathstr = PerlEnv_getenv("PATH");
-    New(0, fullcmd, MAX_PATH+1, char);
+
+    /* worst case: PATH is a single directory; we need additional space
+     * to append "/", ".exe" and trailing "\0" */
+    New(0, fullcmd, (pathstr ? strlen(pathstr) : 0) + cmdlen + 6, char);
     curfullcmd = fullcmd;
 
     while (1) {
@@ -3634,17 +3782,13 @@ qualified_path(const char *cmd)
            if (*pathstr == '"') {      /* foo;"baz;etc";bar */
                pathstr++;              /* skip initial '"' */
                while (*pathstr && *pathstr != '"') {
-                   if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
-                       *curfullcmd++ = *pathstr;
-                   pathstr++;
+                    *curfullcmd++ = *pathstr++;
                }
                if (*pathstr)
                    pathstr++;          /* skip trailing '"' */
            }
            else {
-               if ((STRLEN)(curfullcmd-fullcmd) < MAX_PATH-cmdlen-5)
-                   *curfullcmd++ = *pathstr;
-               pathstr++;
+                *curfullcmd++ = *pathstr++;
            }
        }
        if (*pathstr)
@@ -3919,7 +4063,7 @@ win32_execvp(const char *cmdname, const char *const *argv)
     /* if this is a pseudo-forked child, we just want to spawn
      * the new program, and return */
     if (w32_pseudo_id) {
-       int status = win32_spawnvp(P_WAIT, cmdname, (char *const *)argv);
+       int status = win32_spawnvp(P_WAIT, cmdname, (const char *const *)argv);
        if (status != -1) {
            my_exit(status);
            return 0;
@@ -4012,7 +4156,6 @@ static char *base      = NULL;            /* XXX threadead */
 static char *reserved  = NULL;         /* XXX threadead */
 static char *brk       = NULL;         /* XXX threadead */
 static DWORD pagesize  = 0;            /* XXX threadead */
-static DWORD allocsize = 0;            /* XXX threadead */
 
 void *
 sbrk(ptrdiff_t need)
@@ -4025,28 +4168,34 @@ sbrk(ptrdiff_t need)
     * call the OS to commit just one page ...
     */
    pagesize = info.dwPageSize << 3;
-   allocsize = info.dwAllocationGranularity;
   }
- /* This scheme fails eventually if request for contiguous
-  * block is denied so reserve big blocks - this is only
-  * address space not memory ...
-  */
  if (brk+need >= reserved)
   {
-   DWORD size = 64*1024*1024;
+   DWORD size = brk+need-reserved;
    char *addr;
+   char *prev_committed = NULL;
    if (committed && reserved && committed < reserved)
     {
      /* Commit last of previous chunk cannot span allocations */
      addr = (char *) VirtualAlloc(committed,reserved-committed,MEM_COMMIT,PAGE_READWRITE);
      if (addr)
+      {
+      /* Remember where we committed from in case we want to decommit later */
+      prev_committed = committed;
       committed = reserved;
+      }
     }
    /* Reserve some (more) space
+    * Contiguous blocks give us greater efficiency, so reserve big blocks -
+    * this is only address space not memory...
     * Note this is a little sneaky, 1st call passes NULL as reserved
     * so lets system choose where we start, subsequent calls pass
     * the old end address so ask for a contiguous block
     */
+sbrk_reserve:
+   if (size < 64*1024*1024)
+    size = 64*1024*1024;
+   size = ((size + pagesize - 1) / pagesize) * pagesize;
    addr  = (char *) VirtualAlloc(reserved,size,MEM_RESERVE,PAGE_NOACCESS);
    if (addr)
     {
@@ -4058,6 +4207,19 @@ sbrk(ptrdiff_t need)
      if (!brk)
       brk = committed;
     }
+   else if (reserved)
+    {
+      /* The existing block could not be extended far enough, so decommit
+       * anything that was just committed above and start anew */
+      if (prev_committed)
+       {
+       if (!VirtualFree(prev_committed,reserved-prev_committed,MEM_DECOMMIT))
+        return (void *) -1;
+       }
+      reserved = base = committed = brk = NULL;
+      size = need;
+      goto sbrk_reserve;
+    }
    else
     {
      return (void *) -1;
@@ -4068,11 +4230,12 @@ sbrk(ptrdiff_t need)
  if (brk > committed)
   {
    DWORD size = ((brk-committed + pagesize -1)/pagesize) * pagesize;
-   char *addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
+   char *addr;
+   if (committed+size > reserved)
+    size = reserved-committed;
+   addr = (char *) VirtualAlloc(committed,size,MEM_COMMIT,PAGE_READWRITE);
    if (addr)
-    {
-     committed += size;
-    }
+    committed += size;
    else
     return (void *) -1;
   }
@@ -4377,11 +4540,11 @@ XS(w32_DomainName)
        /* NERR_Success *is* 0*/
        if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
            if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
-               WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
+               WideCharToMultiByte(CP_ACP, 0, pwi->wki100_langroup,
                                    -1, (LPSTR)dname, dnamelen, NULL, NULL);
            }
            else {
-               WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
+               WideCharToMultiByte(CP_ACP, 0, pwi->wki100_computername,
                                    -1, (LPSTR)dname, dnamelen, NULL, NULL);
            }
            pfnNetApiBufferFree(pwi);
@@ -4436,26 +4599,74 @@ static
 XS(w32_GetOSVersion)
 {
     dXSARGS;
-    OSVERSIONINFOA osver;
+    /* Use explicit struct definition because wSuiteMask and
+     * wProductType are not defined in the VC++ 6.0 headers.
+     * WORD type has been replaced by unsigned short because
+     * WORD is already used by Perl itself.
+     */
+    struct {
+        DWORD dwOSVersionInfoSize;
+        DWORD dwMajorVersion;
+        DWORD dwMinorVersion;
+        DWORD dwBuildNumber;
+        DWORD dwPlatformId;
+        CHAR  szCSDVersion[128];
+        unsigned short wServicePackMajor;
+        unsigned short wServicePackMinor;
+        unsigned short wSuiteMask;
+        BYTE  wProductType;
+        BYTE  wReserved;
+    }   osver;
+    BOOL bEx = TRUE;
 
     if (USING_WIDE()) {
-       OSVERSIONINFOW osverw;
+        struct {
+            DWORD dwOSVersionInfoSize;
+            DWORD dwMajorVersion;
+            DWORD dwMinorVersion;
+            DWORD dwBuildNumber;
+            DWORD dwPlatformId;
+            WCHAR szCSDVersion[128];
+            unsigned short wServicePackMajor;
+            unsigned short wServicePackMinor;
+            unsigned short wSuiteMask;
+            BYTE  wProductType;
+            BYTE  wReserved;
+        } osverw;
        char szCSDVersion[sizeof(osverw.szCSDVersion)];
-       osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
-       if (!GetVersionExW(&osverw)) {
-           XSRETURN_EMPTY;
+       osverw.dwOSVersionInfoSize = sizeof(osverw);
+       if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
+            bEx = FALSE;
+            osverw.dwOSVersionInfoSize = sizeof(OSVERSIONINFOW);
+            if (!GetVersionExW((OSVERSIONINFOW*)&osverw)) {
+                XSRETURN_EMPTY;
+            }
+       }
+       if (GIMME_V == G_SCALAR) {
+           XSRETURN_IV(osverw.dwPlatformId);
        }
        W2AHELPER(osverw.szCSDVersion, szCSDVersion, sizeof(szCSDVersion));
        XPUSHs(newSVpvn(szCSDVersion, strlen(szCSDVersion)));
-       osver.dwMajorVersion = osverw.dwMajorVersion;
-       osver.dwMinorVersion = osverw.dwMinorVersion;
-       osver.dwBuildNumber = osverw.dwBuildNumber;
-       osver.dwPlatformId = osverw.dwPlatformId;
+        osver.dwMajorVersion    = osverw.dwMajorVersion;
+        osver.dwMinorVersion    = osverw.dwMinorVersion;
+        osver.dwBuildNumber     = osverw.dwBuildNumber;
+        osver.dwPlatformId      = osverw.dwPlatformId;
+        osver.wServicePackMajor = osverw.wServicePackMajor;
+        osver.wServicePackMinor = osverw.wServicePackMinor;
+        osver.wSuiteMask        = osverw.wSuiteMask;
+        osver.wProductType      = osverw.wProductType;
     }
     else {
-       osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
-       if (!GetVersionExA(&osver)) {
-           XSRETURN_EMPTY;
+       osver.dwOSVersionInfoSize = sizeof(osver);
+       if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
+            bEx = FALSE;
+            osver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
+            if (!GetVersionExA((OSVERSIONINFOA*)&osver)) {
+                XSRETURN_EMPTY;
+            }
+       }
+       if (GIMME_V == G_SCALAR) {
+           XSRETURN_IV(osver.dwPlatformId);
        }
        XPUSHs(newSVpvn(osver.szCSDVersion, strlen(osver.szCSDVersion)));
     }
@@ -4463,6 +4674,12 @@ XS(w32_GetOSVersion)
     XPUSHs(newSViv(osver.dwMinorVersion));
     XPUSHs(newSViv(osver.dwBuildNumber));
     XPUSHs(newSViv(osver.dwPlatformId));
+    if (bEx) {
+        XPUSHs(newSViv(osver.wServicePackMajor));
+        XPUSHs(newSViv(osver.wServicePackMinor));
+        XPUSHs(newSViv(osver.wSuiteMask));
+        XPUSHs(newSViv(osver.wProductType));
+    }
     PUTBACK;
 }
 
@@ -4595,6 +4812,7 @@ XS(w32_GetShortPathName)
     } while (len >= SvLEN(shortpath) && sv_grow(shortpath,len+1));
     if (len) {
        SvCUR_set(shortpath,len);
+       *SvEND(shortpath) = '\0';
        ST(0) = shortpath;
        XSRETURN(1);
     }
@@ -4609,13 +4827,15 @@ XS(w32_GetFullPathName)
     SV *fullpath;
     char *filepart;
     DWORD len;
+    STRLEN filename_len;
+    char *filename_p;
 
     if (items != 1)
        Perl_croak(aTHX_ "usage: Win32::GetFullPathName($filename)");
 
     filename = ST(0);
-    fullpath = sv_mortalcopy(filename);
-    SvUPGRADE(fullpath, SVt_PV);
+    filename_p = SvPV(filename, filename_len);
+    fullpath = sv_2mortal(newSVpvn(filename_p, filename_len));
     if (!SvPVX(fullpath) || !SvLEN(fullpath))
         XSRETURN_UNDEF;
 
@@ -4628,11 +4848,17 @@ XS(w32_GetFullPathName)
     if (len) {
        if (GIMME_V == G_ARRAY) {
            EXTEND(SP,1);
-           XST_mPV(1,filepart);
-           len = filepart - SvPVX(fullpath);
+           if (filepart) {
+               XST_mPV(1,filepart);
+               len = filepart - SvPVX(fullpath);
+           }
+           else {
+               XST_mPVN(1,"",0);
+           }
            items = 2;
        }
        SvCUR_set(fullpath,len);
+       *SvEND(fullpath) = '\0';
        ST(0) = fullpath;
        XSRETURN(items);
     }
@@ -4825,6 +5051,13 @@ Perl_win32_init(int *argcp, char ***argvp)
 }
 
 void
+Perl_win32_term(void)
+{
+    OP_REFCNT_TERM;
+    MALLOC_TERM;
+}
+
+void
 win32_get_child_IO(child_IO_table* ptbl)
 {
     ptbl->childStdIn   = GetStdHandle(STD_INPUT_HANDLE);
@@ -4881,7 +5114,6 @@ Perl_sys_intern_init(pTHX)
     New(1313, w32_pseudo_children, 1, child_tab);
     w32_num_pseudo_children    = 0;
 #  endif
-    w32_init_socktype          = 0;
     w32_timerid                 = 0;
     w32_poll_count              = 0;
     for (i=0; i < SIG_SIZE; i++) {
@@ -4935,7 +5167,6 @@ Perl_sys_intern_dup(pTHX_ struct interp_intern *src, struct interp_intern *dst)
     Newz(1313, dst->children, 1, child_tab);
     dst->pseudo_id             = 0;
     Newz(1313, dst->pseudo_children, 1, child_tab);
-    dst->thr_intern.Winit_socktype = 0;
     dst->timerid                 = 0;
     dst->poll_count              = 0;
     Copy(src->sigtable,dst->sigtable,SIG_SIZE,Sighandler_t);