enable better Win32::DomainName() by demand loading netapi32.dll
[p5sagit/p5-mst-13.2.git] / win32 / win32.c
index 4f0d7f8..3f56f60 100644 (file)
 #endif
 #include <windows.h>
 
-#ifndef __MINGW32__
-#include <lmcons.h>
-#include <lmerr.h>
-/* ugliness to work around a buggy struct definition in lmwksta.h */
-#undef LPTSTR
-#define LPTSTR LPWSTR
-#include <lmwksta.h>
-#undef LPTSTR
-#define LPTSTR LPSTR
-#include <lmapibuf.h>
-#endif /* __MINGW32__ */
-
 /* #include "config.h" */
 
 #define PERLIO_NOT_STDIO 0 
 int _CRT_glob = 0;
 #endif
 
-#ifdef __BORLANDC__
+#if defined(__MINGW32__)
+#  define _stat stat
+#endif
+
+#if defined(__BORLANDC__)
 #  define _stat stat
 #  define _utimbuf utimbuf
 #endif
@@ -94,7 +86,7 @@ int _CRT_glob = 0;
 #endif
 
 static void            get_shell(void);
-static long            tokenize(char *str, char **dest, char ***destv);
+static long            tokenize(const char *str, char **dest, char ***destv);
        int             do_spawn2(char *cmd, int exectype);
 static BOOL            has_shell_metachars(char *ptr);
 static long            filetime_to_clock(PFILETIME ft);
@@ -427,7 +419,7 @@ win32_os_id(void)
  * Returns number of words in result buffer.
  */
 static long
-tokenize(char *str, char **dest, char ***destv)
+tokenize(const char *str, char **dest, char ***destv)
 {
     char *retstart = Nullch;
     char **retvstart = 0;
@@ -485,8 +477,9 @@ get_shell(void)
         *     interactive use (which is what most programs look in COMSPEC
         *     for).
         */
-       char* defaultshell = (IsWinNT() ? "cmd.exe /x/c" : "command.com /c");
-       char *usershell = getenv("PERL5SHELL");
+       const char* defaultshell = (IsWinNT()
+                                   ? "cmd.exe /x/c" : "command.com /c");
+       const char *usershell = getenv("PERL5SHELL");
        w32_perlshell_items = tokenize(usershell ? usershell : defaultshell,
                                       &w32_perlshell_tokens,
                                       &w32_perlshell_vec);
@@ -1296,14 +1289,13 @@ win32_times(struct tms *timebuf)
     return 0;
 }
 
-/* fix utime() so it works on directories in NT
- * thanks to Jan Dubois <jan.dubois@ibm.net>
- */
+/* fix utime() so it works on directories in NT */
 static BOOL
 filetime_from_time(PFILETIME pFileTime, time_t Time)
 {
-    struct tm *pTM = gmtime(&Time);
+    struct tm *pTM = localtime(&Time);
     SYSTEMTIME SystemTime;
+    FILETIME LocalTime;
 
     if (pTM == NULL)
        return FALSE;
@@ -1316,7 +1308,8 @@ filetime_from_time(PFILETIME pFileTime, time_t Time)
     SystemTime.wSecond = pTM->tm_sec;
     SystemTime.wMilliseconds = 0;
 
-    return SystemTimeToFileTime(&SystemTime, pFileTime);
+    return SystemTimeToFileTime(&SystemTime, &LocalTime) &&
+           LocalFileTimeToFileTime(&LocalTime, pFileTime);
 }
 
 DllExport int
@@ -2552,7 +2545,7 @@ win32_spawnvp(int mode, const char *cmdname, const char *const *argv)
     return spawnvp(mode, cmdname, (char * const *)argv);
 #else
     dTHXo;
-    DWORD ret;
+    int ret;
     void* env;
     char* dir;
     STARTUPINFO StartupInfo;
@@ -2629,12 +2622,15 @@ RETRY:
     if (mode == P_NOWAIT) {
        /* asynchronous spawn -- store handle, return PID */
        w32_child_handles[w32_num_children] = ProcessInformation.hProcess;
-       ret = w32_child_pids[w32_num_children] = ProcessInformation.dwProcessId;
+       w32_child_pids[w32_num_children] = ProcessInformation.dwProcessId;
+       ret = (int)ProcessInformation.dwProcessId;
        ++w32_num_children;
     }
     else  {
+       DWORD status;
        WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
-       GetExitCodeProcess(ProcessInformation.hProcess, &ret);
+       GetExitCodeProcess(ProcessInformation.hProcess, &status);
+       ret = (int)status;
        CloseHandle(ProcessInformation.hProcess);
     }
 
@@ -2645,7 +2641,7 @@ RETVAL:
     PerlEnv_free_childdir(dir);
     Safefree(cmd);
     Safefree(fullcmd);
-    return (int)ret;
+    return ret;
 #endif
 }
 
@@ -3006,43 +3002,63 @@ static
 XS(w32_DomainName)
 {
     dXSARGS;
-#ifndef HAS_NETWKSTAGETINFO
-    /* mingw32 (and Win95) don't have NetWksta*(), so do it the old way */
-    char name[256];
-    DWORD size = sizeof(name);
+    HINSTANCE hNetApi32 = LoadLibrary("netapi32.dll");
+    DWORD (__stdcall *pfnNetApiBufferFree)(LPVOID Buffer);
+    DWORD (__stdcall *pfnNetWkstaGetInfo)(LPWSTR servername, DWORD level,
+                                         void *bufptr);
+
+    if (hNetApi32) {
+       pfnNetApiBufferFree = (DWORD (__stdcall *)(void *))
+           GetProcAddress(hNetApi32, "NetApiBufferFree");
+       pfnNetWkstaGetInfo = (DWORD (__stdcall *)(LPWSTR, DWORD, void *))
+           GetProcAddress(hNetApi32, "NetWkstaGetInfo");
+    }
     EXTEND(SP,1);
-    if (GetUserName(name,&size)) {
-       char sid[1024];
-       DWORD sidlen = sizeof(sid);
+    if (hNetApi32 && pfnNetWkstaGetInfo && pfnNetApiBufferFree) {
+       /* this way is more reliable, in case user has a local account. */
        char dname[256];
        DWORD dnamelen = sizeof(dname);
-       SID_NAME_USE snu;
-       if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
-                             dname, &dnamelen, &snu)) {
-           XSRETURN_PV(dname);         /* all that for this */
+       struct {
+           DWORD   wki100_platform_id;
+           LPWSTR  wki100_computername;
+           LPWSTR  wki100_langroup;
+           DWORD   wki100_ver_major;
+           DWORD   wki100_ver_minor;
+       } *pwi;
+       /* NERR_Success *is* 0*/
+       if (0 == pfnNetWkstaGetInfo(NULL, 100, &pwi)) {
+           if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
+               WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
+                                   -1, (LPSTR)dname, dnamelen, NULL, NULL);
+           }
+           else {
+               WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
+                                   -1, (LPSTR)dname, dnamelen, NULL, NULL);
+           }
+           pfnNetApiBufferFree(pwi);
+           FreeLibrary(hNetApi32);
+           XSRETURN_PV(dname);
        }
+       FreeLibrary(hNetApi32);
     }
-#else
-    /* this way is more reliable, in case user has a local account.
-     * XXX need dynamic binding of netapi32.dll symbols or this will fail on
-     * Win95. Probably makes more sense to move it into libwin32. */
-    char dname[256];
-    DWORD dnamelen = sizeof(dname);
-    PWKSTA_INFO_100 pwi;
-    EXTEND(SP,1);
-    if (NERR_Success == NetWkstaGetInfo(NULL, 100, (LPBYTE*)&pwi)) {
-       if (pwi->wki100_langroup && *(pwi->wki100_langroup)) {
-           WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_langroup,
-                               -1, (LPSTR)dname, dnamelen, NULL, NULL);
-       }
-       else {
-           WideCharToMultiByte(CP_ACP, NULL, pwi->wki100_computername,
-                               -1, (LPSTR)dname, dnamelen, NULL, NULL);
+    else {
+       /* Win95 doesn't have NetWksta*(), so do it the old way */
+       char name[256];
+       DWORD size = sizeof(name);
+       if (hNetApi32)
+           FreeLibrary(hNetApi32);
+       if (GetUserName(name,&size)) {
+           char sid[1024];
+           DWORD sidlen = sizeof(sid);
+           char dname[256];
+           DWORD dnamelen = sizeof(dname);
+           SID_NAME_USE snu;
+           if (LookupAccountName(NULL, name, (PSID)&sid, &sidlen,
+                                 dname, &dnamelen, &snu)) {
+               XSRETURN_PV(dname);             /* all that for this */
+           }
        }
-       NetApiBufferFree(pwi);
-       XSRETURN_PV(dname);
     }
-#endif
     XSRETURN_UNDEF;
 }