This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
win32_chdir() et al don't handle a NULL argument gracefully
[perl5.git] / win32 / perlhost.h
index 01ff73d..ca5b498 100644 (file)
@@ -10,6 +10,7 @@
 #ifndef ___PerlHost_H___
 #define ___PerlHost_H___
 
+#include <signal.h>
 #include "iperlsys.h"
 #include "vmem.h"
 #include "vdir.h"
@@ -17,8 +18,9 @@
 #if !defined(PERL_OBJECT)
 START_EXTERN_C
 #endif
-extern char *          g_win32_get_privlib(char *pl);
-extern char *          g_win32_get_sitelib(char *pl);
+extern char *          g_win32_get_privlib(const char *pl);
+extern char *          g_win32_get_sitelib(const char *pl);
+extern char *          g_win32_get_vendorlib(const char *pl);
 extern char *          g_getlogin(void);
 extern int             do_spawn2(char *cmd, int exectype);
 #if !defined(PERL_OBJECT)
@@ -475,17 +477,29 @@ PerlEnvOsId(struct IPerlEnv* piPerl)
 }
 
 char*
-PerlEnvLibPath(struct IPerlEnv* piPerl, char *pl)
+PerlEnvLibPath(struct IPerlEnv* piPerl, const char *pl)
 {
     return g_win32_get_privlib(pl);
 }
 
 char*
-PerlEnvSiteLibPath(struct IPerlEnv* piPerl, char *pl)
+PerlEnvSiteLibPath(struct IPerlEnv* piPerl, const char *pl)
 {
     return g_win32_get_sitelib(pl);
 }
 
+char*
+PerlEnvVendorLibPath(struct IPerlEnv* piPerl, const char *pl)
+{
+    return g_win32_get_vendorlib(pl);
+}
+
+void
+PerlEnvGetChildIO(struct IPerlEnv* piPerl, child_IO_table* ptr)
+{
+    win32_get_child_IO(ptr);
+}
+
 struct IPerlEnv perlEnv = 
 {
     PerlEnvGetenv,
@@ -500,6 +514,8 @@ struct IPerlEnv perlEnv =
     PerlEnvOsId,
     PerlEnvLibPath,
     PerlEnvSiteLibPath,
+    PerlEnvVendorLibPath,
+    PerlEnvGetChildIO,
 };
 
 #undef IPERL2HOST
@@ -924,7 +940,7 @@ PerlLIOFlock(struct IPerlLIO* piPerl, int fd, int oper)
 int
 PerlLIOFileStat(struct IPerlLIO* piPerl, int handle, struct stat *buffer)
 {
-    return fstat(handle, buffer);
+    return win32_fstat(handle, buffer);
 }
 
 int
@@ -1624,11 +1640,11 @@ PerlProcWaitpid(struct IPerlProc* piPerl, int pid, int *status, int flags)
 Sighandler_t
 PerlProcSignal(struct IPerlProc* piPerl, int sig, Sighandler_t subcode)
 {
-    return 0;
+    return signal(sig, subcode);
 }
 
 #ifdef USE_ITHREADS
-static DWORD WINAPI
+static THREAD_RET_TYPE
 win32_start_child(LPVOID arg)
 {
     PerlInterpreter *my_perl = (PerlInterpreter*)arg;
@@ -1643,13 +1659,18 @@ win32_start_child(LPVOID arg)
 #endif
 
 
-    PERL_SET_INTERP(my_perl);
+    PERL_SET_THX(my_perl);
 
     /* set $$ to pseudo id */
 #ifdef PERL_SYNC_FORK
     w32_pseudo_id = id;
 #else
     w32_pseudo_id = GetCurrentThreadId();
+    if (IsWin95()) {
+       int pid = (int)w32_pseudo_id;
+       if (pid < 0)
+           w32_pseudo_id = -pid;
+    }
 #endif
     if (tmpgv = gv_fetchpv("$", TRUE, SVt_PV))
        sv_setiv(GvSV(tmpgv), -(IV)w32_pseudo_id);
@@ -1657,7 +1678,7 @@ win32_start_child(LPVOID arg)
 
     /* push a zero on the stack (we are the child) */
     {
-       djSP;
+       dSP;
        dTARGET;
        PUSHi(0);
        PUTBACK;
@@ -1668,7 +1689,7 @@ win32_start_child(LPVOID arg)
 
     {
        dJMPENV;
-       volatile oldscope = PL_scopestack_ix;
+       volatile int oldscope = PL_scopestack_ix;
 
 restart:
        JMPENV_PUSH(status);
@@ -1704,6 +1725,13 @@ restart:
        PL_main_root = Nullop;
     }
 
+    /* close the std handles to avoid fd leaks */
+    {
+       do_close(gv_fetchpv("STDIN", TRUE, SVt_PVIO), FALSE);
+       do_close(gv_fetchpv("STDOUT", TRUE, SVt_PVIO), FALSE);
+       do_close(gv_fetchpv("STDERR", TRUE, SVt_PVIO), FALSE);
+    }
+
     /* destroy everything (waits for any pseudo-forked children) */
     perl_destruct(my_perl);
     perl_free(my_perl);
@@ -1723,7 +1751,13 @@ PerlProcFork(struct IPerlProc* piPerl)
 #ifdef USE_ITHREADS
     DWORD id;
     HANDLE handle;
-    CPerlHost *h = new CPerlHost();
+    CPerlHost *h;
+
+    if (w32_num_pseudo_children >= MAXIMUM_WAIT_OBJECTS) {
+       errno = EAGAIN;
+       return -1;
+    }
+    h = new CPerlHost(*(CPerlHost*)w32_internal_host);
     PerlInterpreter *new_perl = perl_clone_using((PerlInterpreter*)aTHXo, 1,
                                                 h->m_pHostperlMem,
                                                 h->m_pHostperlMemShared,
@@ -1735,15 +1769,28 @@ PerlProcFork(struct IPerlProc* piPerl)
                                                 h->m_pHostperlSock,
                                                 h->m_pHostperlProc
                                                 );
+    new_perl->Isys_intern.internal_host = h;
 #  ifdef PERL_SYNC_FORK
     id = win32_start_child((LPVOID)new_perl);
-    PERL_SET_INTERP(aTHXo);
+    PERL_SET_THX(aTHXo);
 #  else
+#    ifdef USE_RTL_THREAD_API
+    handle = (HANDLE)_beginthreadex((void*)NULL, 0, win32_start_child,
+                                   (void*)new_perl, 0, (unsigned*)&id);
+#    else
     handle = CreateThread(NULL, 0, win32_start_child,
                          (LPVOID)new_perl, 0, &id);
-    PERL_SET_INTERP(aTHXo);
-    if (!handle)
-       Perl_croak(aTHX_ "panic: pseudo fork() failed");
+#    endif
+    PERL_SET_THX(aTHXo);       /* XXX perl_clone*() set TLS */
+    if (!handle) {
+       errno = EAGAIN;
+       return -1;
+    }
+    if (IsWin95()) {
+       int pid = (int)id;
+       if (pid < 0)
+           id = -pid;
+    }
     w32_pseudo_child_handles[w32_num_pseudo_children] = handle;
     w32_pseudo_child_pids[w32_num_pseudo_children] = id;
     ++w32_num_pseudo_children;
@@ -1890,7 +1937,7 @@ CPerlHost::CPerlHost(struct IPerlMem** ppMem, struct IPerlMem** ppMemShared,
                 struct IPerlDir** ppDir, struct IPerlSock** ppSock,
                 struct IPerlProc** ppProc)
 {
-    m_pvDir = new VDir();
+    m_pvDir = new VDir(0);
     m_pVMem = new VMem();
     m_pVMemShared = new VMem();
     m_pVMemParse =  new VMem();
@@ -1929,7 +1976,7 @@ CPerlHost::CPerlHost(CPerlHost& host)
     m_pVMemParse =  host.GetMemParse();
 
     /* duplicate directory info */
-    m_pvDir = new VDir();
+    m_pvDir = new VDir(0);
     m_pvDir->Init(host.GetDir(), m_pVMem);
 
     CopyMemory(&m_hostperlMem, &perlMem, sizeof(perlMem));
@@ -1941,15 +1988,15 @@ CPerlHost::CPerlHost(CPerlHost& host)
     CopyMemory(&m_hostperlDir, &perlDir, sizeof(perlDir));
     CopyMemory(&m_hostperlSock, &perlSock, sizeof(perlSock));
     CopyMemory(&m_hostperlProc, &perlProc, sizeof(perlProc));
-    m_pHostperlMem         = &host.m_hostperlMem;
-    m_pHostperlMemShared    = &host.m_hostperlMemShared;
-    m_pHostperlMemParse            = &host.m_hostperlMemParse;
-    m_pHostperlEnv         = &host.m_hostperlEnv;
-    m_pHostperlStdIO       = &host.m_hostperlStdIO;
-    m_pHostperlLIO         = &host.m_hostperlLIO;
-    m_pHostperlDir         = &host.m_hostperlDir;
-    m_pHostperlSock        = &host.m_hostperlSock;
-    m_pHostperlProc        = &host.m_hostperlProc;
+    m_pHostperlMem         = &m_hostperlMem;
+    m_pHostperlMemShared    = &m_hostperlMemShared;
+    m_pHostperlMemParse            = &m_hostperlMemParse;
+    m_pHostperlEnv         = &m_hostperlEnv;
+    m_pHostperlStdIO       = &m_hostperlStdIO;
+    m_pHostperlLIO         = &m_hostperlLIO;
+    m_pHostperlDir         = &m_hostperlDir;
+    m_pHostperlSock        = &m_hostperlSock;
+    m_pHostperlProc        = &m_hostperlProc;
 
     m_dwEnvCount = 0;
     m_lppEnvList = NULL;
@@ -2118,10 +2165,10 @@ CPerlHost::GetChildDir(void)
     New(0, ptr, MAX_PATH+1, char);
     if(ptr) {
        m_pvDir->GetCurrentDirectoryA(MAX_PATH+1, ptr);
-       length = strlen(ptr)-1;
-       if(length > 0) {
-           if((ptr[length] == '\\') || (ptr[length] == '/'))
-               ptr[length] = 0;
+       length = strlen(ptr);
+       if (length > 3) {
+           if ((ptr[length-1] == '\\') || (ptr[length-1] == '/'))
+               ptr[length-1] = 0;
        }
     }
     return ptr;
@@ -2171,7 +2218,7 @@ CPerlHost::CreateLocalEnvironmentStrings(VDir &vDir)
        dwEnvIndex = 0;
        lpLocalEnv = GetIndex(dwEnvIndex);
        while(*lpEnvPtr != '\0') {
-           if(lpLocalEnv == NULL) {
+           if(!lpLocalEnv) {
                // all environment overrides have been added
                // so copy string into place
                strcpy(lpStr, lpEnvPtr);
@@ -2203,6 +2250,16 @@ CPerlHost::CreateLocalEnvironmentStrings(VDir &vDir)
            }
        }
 
+       while(lpLocalEnv) {
+           // still have environment overrides to add
+           // so copy the strings into place
+           strcpy(lpStr, lpLocalEnv);
+           nLength = strlen(lpLocalEnv) + 1;
+           lpStr += nLength;
+           lpEnvPtr += nLength;
+           lpLocalEnv = GetIndex(dwEnvIndex);
+       }
+
        // add final NULL
        *lpStr = '\0';
     }
@@ -2229,9 +2286,10 @@ CPerlHost::Reset(void)
 void
 CPerlHost::Clearenv(void)
 {
+    dTHXo;
     char ch;
     LPSTR lpPtr, lpStr, lpEnvPtr;
-    if(m_lppEnvList != NULL) {
+    if (m_lppEnvList != NULL) {
        /* set every entry to an empty string */
        for(DWORD index = 0; index < m_dwEnvCount; ++index) {
            char* ptr = strchr(m_lppEnvList[index], '=');
@@ -2254,6 +2312,8 @@ CPerlHost::Clearenv(void)
            ch = *++lpPtr;
            *lpPtr = 0;
            Add(lpStr);
+           if (!w32_pseudo_id)
+               (void)win32_putenv(lpStr);
            *lpPtr = ch;
        }
        lpStr += strlen(lpStr) + 1;
@@ -2266,22 +2326,23 @@ CPerlHost::Clearenv(void)
 char*
 CPerlHost::Getenv(const char *varname)
 {
-    char* pEnv = Find(varname);
-    if(pEnv == NULL) {
-       pEnv = win32_getenv(varname);
-    }
-    else {
-       if(!*pEnv)
-           pEnv = 0;
+    dTHXo;
+    if (w32_pseudo_id) {
+       char *pEnv = Find(varname);
+       if (pEnv && *pEnv)
+           return pEnv;
     }
-
-    return pEnv;
+    return win32_getenv(varname);
 }
 
 int
 CPerlHost::Putenv(const char *envstring)
 {
+    dTHXo;
     Add(envstring);
+    if (!w32_pseudo_id)
+       return win32_putenv(envstring);
+
     return 0;
 }
 
@@ -2290,6 +2351,10 @@ CPerlHost::Chdir(const char *dirname)
 {
     dTHXo;
     int ret;
+    if (!dirname) {
+       errno = ENOENT;
+       return -1;
+    }
     if (USING_WIDE()) {
        WCHAR wBuffer[MAX_PATH];
        A2WHELPER(dirname, wBuffer, sizeof(wBuffer));