dveditz%netscape.com 1ff29abbe0 merging in changes from Classic branch. Not part of SeaMonkey build (yet)
git-svn-id: svn://10.0.0.236/trunk@17772 18797224-902f-48f8-a5cc-f745e15eee43
1999-01-14 23:08:21 +00:00

593 lines
16 KiB
C++

/* -*- Mode: C++; tab-width: 4; tabs-indent-mode: nil -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/* su_win.c
* Win specific softupdate routines
*/
#ifdef XP_OS2
#include os2updt.h"
#endif
#include <stdafx.h>
#include "xp_mcom.h"
#include "su_folderspec.h"
#include "su_instl.h"
#include "xp_str.h"
#include "npapi.h"
#include "libevent.h"
#include "fe_proto.h"
#include "xpgetstr.h"
#include <windows.h>
#include "NSReg.h"
#ifdef WIN32
#include <winver.h>
#elif !defined (XP_OS2)
#include <ver.h>
#endif
extern NPError wfe_GetPluginsDirectory(CString& csDirname);
extern "C" char * FE_GetProgramDirectory(char *buffer, int length);
extern "C" int SU_NEED_TO_REBOOT;
XP_Bool fe_FileNeedsUpdate(char *sourceFile, char *targetFile);
#if defined(WIN32) || defined(XP_OS2)
#define su_FileRemove(file,type) XP_FileRemove((file),(type))
#else
int su_FileRemove(char *fname, XP_FileType type);
#endif
char * FE_GetDirectoryPath( su_DirSpecID folderID)
{
char * directory = NULL;
char path[_MAX_PATH];
DWORD dwVersion;
UINT len;
switch( folderID)
{
case ePluginFolder:
{
NPError err;
CString c;
err = wfe_GetPluginsDirectory(c);
if (err == 0) {
c += (TCHAR)'\\';
directory = XP_STRDUP( c );
}
}
break;
case eProgramFolder:
FE_GetProgramDirectory( path, _MAX_PATH );
directory = XP_STRDUP( path );
break;
case ePackageFolder:
break;
case eTemporaryFolder:
{
char* tmpdir = XP_TempDirName();
int slen;
XP_STRNCPY_SAFE( path, tmpdir, _MAX_PATH );
XP_FREEIF(tmpdir);
slen = XP_STRLEN(path);
if ( slen < _MAX_PATH - 1)
{
path[slen] = '\\';
path[slen+1] = '\0';
}
else
break;
directory = XP_STRDUP( path );
}
break;
case eCommunicatorFolder:
{
char* p;
FE_GetProgramDirectory( path, _MAX_PATH );
if ( (p = XP_STRRCHR( path, '\\' )) ) *p = '\0';
if ( (p = XP_STRRCHR( path, '\\' )) ) p[1] = '\0';
directory = XP_STRDUP( path );
}
break;
case eWin_System16Folder:
len = GetSystemDirectory( path, _MAX_PATH );
#ifndef XP_OS2
// If Windows NT
dwVersion = GetVersion();
if ( dwVersion < 0x80000000 ) {
// and the last two chars of the system dir are "32"
if ( XP_STRCMP( path+len-2, "32" ) == 0 ) {
// 16-bit system dir is just "System"
len = len - 2;
}
}
#endif
// Need enough space to add the trailing backslash
if(len > _MAX_PATH-2)
break;
path[len] = '\\';
path[len+1] = '\0';
directory = XP_STRDUP( path );
break;
case eWin_SystemFolder:
len = GetSystemDirectory( path, _MAX_PATH );
// Need enough space to add the trailing backslash
if(len > _MAX_PATH-2)
break;
path[len] = '\\';
path[len+1] = '\0';
directory = XP_STRDUP( path );
break;
case eWin_WindowsFolder:
len = GetWindowsDirectory( path, _MAX_PATH );
// Need enough space to add the trailing backslash
if(len > _MAX_PATH-2)
break;
path[len] = '\\';
path[len+1] = '\0';
directory = XP_STRDUP( path );
break;
case eJavaBinFolder:
FE_GetProgramDirectory( path, _MAX_PATH );
directory = PR_smprintf("%sjava\\bin\\", path);
break;
case eJavaClassesFolder:
FE_GetProgramDirectory( path, _MAX_PATH );
directory = PR_smprintf("%sjava\\classes\\", path);
break;
case eJavaDownloadFolder:
FE_GetProgramDirectory( path, _MAX_PATH );
directory = PR_smprintf("%sjava\\download\\", path);
break;
case eNetHelpFolder:
{
char* tmpdir = FE_GetNetHelpDir();
if ('/' != *tmpdir ) {
/* we got a valid file url from FE_GetNetHelpDir() */
directory = WH_FileName(tmpdir+7, xpURL);
}
else {
/* windows FE couldn't find registry setting */
FE_GetProgramDirectory( path, _MAX_PATH );
if(strlen(path)+strlen("NetHelp\\")+1 > _MAX_PATH)
break;
XP_STRCAT( path, "NetHelp\\" );
directory = XP_STRDUP( path );
}
XP_FREEIF(tmpdir);
}
break;
case eOSDriveFolder:
len = GetWindowsDirectory( path, _MAX_PATH );
if (len)
{
if ( path[1] == ':' && path[2] == '\\' )
{
path[3] = 0;
directory = XP_STRDUP( path );
}
}
break;
// inapplicable platform specific directories
case eMac_SystemFolder:
case eMac_DesktopFolder:
case eMac_TrashFolder:
case eMac_StartupFolder:
case eMac_ShutdownFolder:
case eMac_AppleMenuFolder:
case eMac_ControlPanelFolder:
case eMac_ExtensionFolder:
case eMac_FontsFolder:
case eMac_PreferencesFolder:
case eUnix_LocalFolder:
case eUnix_LibFolder:
break;
case eFileURLFolder: // should never be handled in this routine
default:
// someone added a new one and didn't take care of it
XP_ASSERT(0);
break;
}
return directory;
}
int FE_ExecuteFile( const char * filename, const char * cmdline )
{
if ( cmdline == NULL || filename == NULL )
return -1;
DWORD hInst = WinExec( cmdline, SW_NORMAL );
su_DeleteOldFileLater( (char*)filename );
if ( hInst < 32 )
return -1;
else
return 0;
}
/* Template for a delayed "rename" of a file on windows platform, need to:
- Convert filenames to native form
- Add error checking
*/
#ifndef NO_ERROR
#define NO_ERROR 0
#endif
int FE_ReplaceExistingFile(char *CurrentFname, XP_FileType ctype,
char *FinalFname, XP_FileType ftype, XP_Bool force)
{
int err;
char * currentName;
char * finalName;
/* Convert file names to their native format */
currentName = WH_FileName (CurrentFname, ctype);
finalName = WH_FileName (FinalFname, ftype);
if ( currentName == NULL || finalName == NULL ) {
err = -1;
goto cleanup;
}
// replace file if forced or if windows version info is newer
if (force || fe_FileNeedsUpdate( currentName, finalName ) )
{
/* try to delete the existing file */
err = su_FileRemove( FinalFname, ftype );
if ( NO_ERROR == err )
{
err = XP_FileRename(CurrentFname, ctype, FinalFname, ftype);
}
else
{
/* couldn't delete, probably in use. Schedule for later */
DWORD dwVersion, dwWindowsMajorVersion;
char* final = finalName;
char* current = currentName;
#if !defined(XP_OS2)
#if !defined(XP_WIN16)
/* Get OS version info */
dwVersion = GetVersion();
dwWindowsMajorVersion = (DWORD)(LOBYTE(LOWORD(dwVersion)));
/* Get build numbers for Windows NT or Win32s */
if (dwVersion < 0x80000000) // Windows NT
{
/* On Windows NT */
if ( WFE_IsMoveFileExBroken() )
{
/* the MOVEFILE_DELAY_UNTIL_REBOOT option doesn't work on
* NT 3.51 SP4 or on NT 4.0 until SP2
*/
struct stat statbuf;
BOOL nameFound = FALSE;
char tmpname[_MAX_PATH];
XP_STRNCPY_SAFE( tmpname, finalName, _MAX_PATH );
int len = strlen(tmpname);
while (!nameFound && len < _MAX_PATH ) {
tmpname[len-1] = '~';
tmpname[len] = '\0';
if ( stat(tmpname, &statbuf) != 0 )
nameFound = TRUE;
else
len++;
}
if ( nameFound ) {
if ( MoveFile( finalName, tmpname ) ) {
if ( MoveFile( currentName, finalName ) ) {
err = su_DeleteOldFileLater( tmpname );
}
else {
/* 2nd move failed, put old file back */
MoveFile( tmpname, finalName );
}
}
else {
/* non-executable in use; schedule for later */
err = su_ReplaceOldFileLater( CurrentFname, FinalFname );
}
}
}
else if ( MoveFileEx(currentName, finalName, MOVEFILE_DELAY_UNTIL_REBOOT) )
{
err = NO_ERROR;
}
}
else // Windows 95 or Win16
{
/*
* Place an entry in the WININIT.INI file in the Windows directory
* to delete finalName and rename currentName to be finalName at reboot
*/
int strlen;
char Src[_MAX_PATH]; // 8.3 name
char Dest[_MAX_PATH]; // 8.3 name
strlen = GetShortPathName( (LPCTSTR)currentName, (LPTSTR)Src, (DWORD)sizeof(Src) );
if ( strlen > 0 ) {
current = Src;
}
strlen = GetShortPathName( (LPCTSTR) finalName, (LPTSTR) Dest, (DWORD) sizeof(Dest));
if ( strlen > 0 ) {
final = Dest;
}
#endif /* !XP_WIN16 */
/* NOTE: use OEM filenames! Even though it looks like a Windows
* .INI file, WININIT.INI is processed under DOS
*/
AnsiToOem( final, final );
AnsiToOem( current, current );
if ( WritePrivateProfileString( "Rename", final, current, "WININIT.INI" ) )
err = NO_ERROR;
#if !defined(XP_WIN16)
}
#endif /* XP_WIN16 */
#else /* XP_OS2 */
ULONG usRetCode;
usRetCode = WriteLockFileRenameEntry(final,current,"SOFTUPDT.LST");
if (usRetCode == NO_ERROR) {
err = NO_ERROR;
}
#endif /* XP_OS2 */
if ( NO_ERROR == err )
err = SU_REBOOT_NEEDED;
}
} // (force || fe_FileNeedsUpdate( currentName, finalName ))
else {
// file to be installed was older than existing file--clean up
err = XP_FileRemove( CurrentFname, ctype );
}
cleanup:
XP_FREEIF(finalName);
XP_FREEIF(currentName);
return err;
}
void PR_CALLBACK SU_AlertCallback(void * dummy)
{
MWContext * cx;
cx = XP_FindSomeContext();
FE_Alert(cx, XP_GetString(SU_NEED_TO_REBOOT));
}
XP_Bool fe_FileNeedsUpdate(char *sourceFile, char *targetFile)
{
XP_Bool needUpdate;
#if defined XP_OS2
needUpdate = TRUE; //Do not have internal version control so
//assume that files should be replaced as
//in unix version
#else
DWORD targetInfoSize;
DWORD sourceInfoSize;
DWORD bogusHandle;
void *sourceData;
void *targetData;
VS_FIXEDFILEINFO *sourceInfo;
VS_FIXEDFILEINFO *targetInfo;
UINT targIBSize;
UINT srcIBSize;
// always replace old file if it doesn't have version info
targetInfoSize = GetFileVersionInfoSize( targetFile, &bogusHandle );
if (targetInfoSize == 0)
return TRUE;
// if new file doesn't have a version assume it's older than one that does
sourceInfoSize = GetFileVersionInfoSize( sourceFile, &bogusHandle );
if (sourceInfoSize == 0)
return FALSE;
// both files have version info blocks; we must compare them
needUpdate = TRUE;
sourceData = XP_ALLOC(sourceInfoSize);
targetData = XP_ALLOC(targetInfoSize);
if ( (sourceData != NULL) && (targetData != NULL) &&
GetFileVersionInfo(targetFile, NULL, targetInfoSize, targetData) &&
GetFileVersionInfo(sourceFile, NULL, sourceInfoSize, sourceData) &&
VerQueryValue(targetData, "\\", (void**)&targetInfo, &targIBSize) &&
VerQueryValue(sourceData, "\\", (void**)&sourceInfo, &srcIBSize) )
{
DWORD targetMajorVer = targetInfo->dwFileVersionMS;
DWORD targetMinorVer = targetInfo->dwFileVersionLS;
DWORD sourceMajorVer = sourceInfo->dwFileVersionMS;
DWORD sourceMinorVer = sourceInfo->dwFileVersionLS;
// don't replace a file with a newer version
if (targetMajorVer > sourceMajorVer)
{
needUpdate = FALSE;
}
else if (targetMajorVer == sourceMajorVer && targetMinorVer > sourceMinorVer)
{
needUpdate = FALSE;
}
else
needUpdate = TRUE;
}
XP_FREEIF(sourceData);
XP_FREEIF(targetData);
#endif //XP_OS2
return needUpdate;
}
#if !defined(WIN32) && !defined(XP_OS2)
#define BUFLEN 1024
void FE_ScheduleRenameUtility(void)
{
int cmdlength;
char *folder;
char * buf = (char*)XP_ALLOC(BUFLEN);
if ( buf != NULL ) {
FE_GetProgramDirectory(buf, BUFLEN);
XP_STRCAT(buf, "NSINIT.EXE,");
cmdlength = XP_STRLEN(buf);
if (!GetProfileString("Windows","Run","",(buf+cmdlength),
(BUFLEN-cmdlength)))
{
// no other RUN commands so don't need trailing comma
buf[cmdlength-1] = '\0';
}
WriteProfileString("Windows","Run",buf);
XP_FREE(buf);
}
}
// WIN16 only, Win32 is macro'd to usual XP_FileRemove()
int su_FileRemove(char *fname, XP_FileType type)
{
HMODULE hinst;
char *pFile;
int err = NO_ERROR;
// convert to native filename and see if it's currently running
pFile = WH_FileName( fname, type );
if (pFile != NULL ) {
// Don't try to delete if Windows says it's in use
hinst = GetModuleHandle(pFile);
if ( hinst != NULL ) {
// GetModuleHandle() accepts the full path but matches only on the
// root name. Use GetModuleFileName() to verify a true match
char module[_MAX_PATH];
GetModuleFileName( hinst, module, _MAX_PATH );
if ( stricmp( pFile, module ) == 0 ) {
// they match
err = -1;
}
}
XP_FREE(pFile);
}
if ( err == NO_ERROR ) {
// wasn't in use (or couldn't convert to native filename)
// try to remove the old way
err = XP_FileRemove( fname, type );
}
return err;
}
#endif /* !WIN32 */
#ifdef WIN32
BOOL WFE_IsMoveFileExBroken()
{
/* the NT option MOVEFILE_DELAY_UNTIL_REBOOT is broken on
* Windows NT 3.51 Service Pack 4 and NT 4.0 before Service Pack 2
*/
BOOL broken = FALSE;
OSVERSIONINFO osinfo;
// they *all* appear broken--better to have one way that works.
return TRUE;
osinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (GetVersionEx(&osinfo) && osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
if ( osinfo.dwMajorVersion == 3 && osinfo.dwMinorVersion == 51 )
{
if ( 0 == stricmp(osinfo.szCSDVersion,"Service Pack 4"))
{
broken = TRUE;
}
}
else if ( osinfo.dwMajorVersion == 4 )
{
if (osinfo.szCSDVersion[0] == '\0' ||
(0 == stricmp(osinfo.szCSDVersion,"Service Pack 1")))
{
broken = TRUE;
}
}
}
return broken;
}
#endif /* WIN32 */