1999-03-24 05:16:41 +03:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/*
|
|
|
|
* The contents of this file are subject to the Netscape Public License
|
|
|
|
* Version 1.0 (the "License"); you may not use this file except in
|
|
|
|
* compliance with the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is Mozilla Communicator client code,
|
|
|
|
* released March 31, 1998.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is Netscape Communications
|
|
|
|
* Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* Daniel Veditz <dveditz@netscape.com>
|
|
|
|
* Douglas Turner <dougt@netscape.com>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "nscore.h"
|
|
|
|
#include "NSReg.h"
|
|
|
|
#include "nsFileSpec.h"
|
1999-05-07 04:05:54 +04:00
|
|
|
#include "nsFileStream.h"
|
|
|
|
#include "nsInstall.h" // for error codes
|
|
|
|
#include "prmem.h"
|
1999-05-28 01:02:57 +04:00
|
|
|
#include "ScheduledTasks.h"
|
1999-03-24 05:16:41 +03:00
|
|
|
|
1999-05-28 01:02:57 +04:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <windows.h>
|
|
|
|
|
|
|
|
BOOL WIN32_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PRInt32 DoWindowsReplaceExistingFileStuff(const char* currentName, const char* finalName)
|
|
|
|
{
|
|
|
|
PRInt32 err = 0;
|
|
|
|
|
|
|
|
char* final = strdup(finalName);
|
|
|
|
char* current = strdup(currentName);
|
|
|
|
|
|
|
|
/* couldn't delete, probably in use. Schedule for later */
|
|
|
|
DWORD dwVersion, dwWindowsMajorVersion;
|
|
|
|
|
|
|
|
/* 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 ( WIN32_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;
|
|
|
|
PRBool nameFound = PR_FALSE;
|
|
|
|
char tmpname[_MAX_PATH];
|
|
|
|
|
|
|
|
strncpy( 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 ) )
|
|
|
|
{
|
|
|
|
DeleteFileNowOrSchedule(nsFileSpec(tmpname));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* 2nd move failed, put old file back */
|
|
|
|
MoveFile( tmpname, finalName );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* non-executable in use; schedule for later */
|
|
|
|
return -1; // let the start registry stuff do our work!
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( MoveFileEx(currentName, finalName, MOVEFILE_DELAY_UNTIL_REBOOT) )
|
|
|
|
{
|
|
|
|
err = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 )
|
|
|
|
{
|
|
|
|
free(current);
|
|
|
|
current = strdup(Src);
|
|
|
|
}
|
|
|
|
|
|
|
|
strlen = GetShortPathName( (LPCTSTR) finalName, (LPTSTR) Dest, (DWORD) sizeof(Dest));
|
|
|
|
if ( strlen > 0 )
|
|
|
|
{
|
|
|
|
free(final);
|
|
|
|
final = strdup(Dest);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
free(final);
|
|
|
|
free(current);
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-07-01 09:51:24 +04:00
|
|
|
REGERR DeleteFileNowOrSchedule(const nsFileSpec& filename)
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
|
|
|
|
REGERR result = 0;
|
1999-07-08 05:38:55 +04:00
|
|
|
char szValue[512];
|
1999-05-07 04:05:54 +04:00
|
|
|
|
1999-07-08 05:38:55 +04:00
|
|
|
PL_strcpy(szValue, "Fix for bug #8818");
|
|
|
|
|
1999-06-25 00:20:12 +04:00
|
|
|
filename.Delete(PR_FALSE);
|
1999-05-07 04:05:54 +04:00
|
|
|
|
|
|
|
if (filename.Exists())
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
RKEY newkey;
|
|
|
|
HREG reg;
|
|
|
|
if ( REGERR_OK == NR_RegOpen("", ®) )
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
if (REGERR_OK == NR_RegAddKey( reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY, &newkey) )
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
// FIX should be using nsPersistentFileDescriptor!!!
|
1999-05-07 04:05:54 +04:00
|
|
|
|
1999-07-08 05:38:55 +04:00
|
|
|
result = NR_RegSetEntry( reg, newkey, (char*)(const char*)filename.GetNativePathCString(), REGTYPE_ENTRY_FILE, szValue, strlen(szValue));
|
1999-05-07 04:05:54 +04:00
|
|
|
if (result == REGERR_OK)
|
|
|
|
result = nsInstall::REBOOT_NEEDED;
|
|
|
|
}
|
1999-03-24 05:16:41 +03:00
|
|
|
|
1999-05-07 04:05:54 +04:00
|
|
|
NR_RegClose(reg);
|
|
|
|
}
|
1999-03-24 05:16:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
1999-05-18 01:28:56 +04:00
|
|
|
/* tmp file is the bad one that we want to replace with target. */
|
1999-03-24 05:16:41 +03:00
|
|
|
|
1999-05-28 01:02:57 +04:00
|
|
|
REGERR ReplaceFileNowOrSchedule(nsFileSpec& replacementFile, nsFileSpec& doomedFile )
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
REGERR result = 0;
|
|
|
|
|
1999-05-18 01:28:56 +04:00
|
|
|
if(replacementFile == doomedFile)
|
|
|
|
{
|
|
|
|
/* do not have to do anything */
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
1999-06-25 00:20:12 +04:00
|
|
|
doomedFile.Delete(PR_FALSE);
|
1999-05-18 01:28:56 +04:00
|
|
|
|
1999-06-05 01:54:34 +04:00
|
|
|
if ( !doomedFile.Exists() )
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-06-05 01:54:34 +04:00
|
|
|
// Now that we have removed the existing file, we can move the mExtracedFile or mPatchedFile into place.
|
1999-05-07 04:05:54 +04:00
|
|
|
nsFileSpec parentofFinalFile;
|
|
|
|
|
1999-05-18 01:28:56 +04:00
|
|
|
doomedFile.GetParent(parentofFinalFile);
|
|
|
|
result = replacementFile.Move(parentofFinalFile);
|
1999-05-28 01:02:57 +04:00
|
|
|
if ( NS_SUCCEEDED(result) )
|
|
|
|
{
|
|
|
|
char* leafName = doomedFile.GetLeafName();
|
|
|
|
replacementFile.Rename(leafName);
|
|
|
|
nsCRT::free(leafName);
|
|
|
|
}
|
1999-05-07 04:05:54 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
#ifdef _WINDOWS
|
|
|
|
if (DoWindowsReplaceExistingFileStuff(replacementFile.GetNativePathCString(), doomedFile.GetNativePathCString()) == 0)
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
|
1999-05-07 04:05:54 +04:00
|
|
|
RKEY newkey;
|
|
|
|
HREG reg;
|
|
|
|
|
|
|
|
if ( REGERR_OK == NR_RegOpen("", ®) )
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
result = NR_RegAddKey( reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY, &newkey);
|
|
|
|
if ( result == REGERR_OK )
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
char* replacementFileName = (char*)(const char*)replacementFile.GetNativePathCString();
|
|
|
|
result = NR_RegSetEntry( reg, newkey, (char*)(const char*)doomedFile.GetNativePathCString(), REGTYPE_ENTRY_FILE, replacementFileName, strlen(replacementFileName));
|
1999-05-07 04:05:54 +04:00
|
|
|
if (result == REGERR_OK)
|
|
|
|
result = nsInstall::REBOOT_NEEDED;
|
|
|
|
}
|
|
|
|
|
|
|
|
NR_RegClose(reg);
|
1999-03-24 05:16:41 +03:00
|
|
|
}
|
|
|
|
}
|
1999-05-07 04:05:54 +04:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DeleteScheduledFiles(void);
|
|
|
|
void ReplaceScheduledFiles(void);
|
|
|
|
|
|
|
|
extern "C" void PerformScheduledTasks(void *data)
|
|
|
|
{
|
|
|
|
DeleteScheduledFiles();
|
|
|
|
ReplaceScheduledFiles();
|
1999-03-24 05:16:41 +03:00
|
|
|
}
|
|
|
|
|
1999-05-07 04:05:54 +04:00
|
|
|
|
1999-03-24 05:16:41 +03:00
|
|
|
void DeleteScheduledFiles(void)
|
|
|
|
{
|
|
|
|
HREG reg;
|
|
|
|
|
|
|
|
if (REGERR_OK == NR_RegOpen("", ®))
|
|
|
|
{
|
|
|
|
RKEY key;
|
1999-07-08 05:38:55 +04:00
|
|
|
REGENUM state = 0;
|
1999-03-24 05:16:41 +03:00
|
|
|
|
|
|
|
/* perform scheduled file deletions and replacements (PC only) */
|
|
|
|
if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY,&key))
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
char buf[MAXREGNAMELEN];
|
1999-03-24 05:16:41 +03:00
|
|
|
|
|
|
|
while (REGERR_OK == NR_RegEnumEntries(reg, key, &state, buf, sizeof(buf), NULL ))
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
nsFileSpec doomedFile(buf);
|
1999-03-24 05:16:41 +03:00
|
|
|
|
|
|
|
doomedFile.Delete(PR_FALSE);
|
|
|
|
|
|
|
|
if (! doomedFile.Exists())
|
|
|
|
{
|
|
|
|
NR_RegDeleteEntry( reg, key, buf );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* delete list node if empty */
|
1999-07-08 05:38:55 +04:00
|
|
|
if (REGERR_NOMORE == NR_RegEnumEntries( reg, key, &state, buf, sizeof(buf), NULL ))
|
1999-03-24 05:16:41 +03:00
|
|
|
{
|
|
|
|
NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_DELETE_LIST_KEY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NR_RegClose(reg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ReplaceScheduledFiles(void)
|
|
|
|
{
|
|
|
|
HREG reg;
|
|
|
|
|
|
|
|
if (REGERR_OK == NR_RegOpen("", ®))
|
|
|
|
{
|
|
|
|
RKEY key;
|
|
|
|
REGENUM state;
|
|
|
|
|
|
|
|
/* replace files if any listed */
|
|
|
|
if (REGERR_OK == NR_RegGetKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY, &key))
|
|
|
|
{
|
|
|
|
char tmpfile[MAXREGNAMELEN];
|
|
|
|
char target[MAXREGNAMELEN];
|
|
|
|
|
|
|
|
state = 0;
|
|
|
|
while (REGERR_OK == NR_RegEnumEntries(reg, key, &state, tmpfile, sizeof(tmpfile), NULL ))
|
|
|
|
{
|
1999-05-07 04:05:54 +04:00
|
|
|
|
1999-05-28 01:02:57 +04:00
|
|
|
nsFileSpec replaceFile(tmpfile);
|
1999-03-24 05:16:41 +03:00
|
|
|
|
|
|
|
if (! replaceFile.Exists() )
|
|
|
|
{
|
|
|
|
NR_RegDeleteEntry( reg, key, tmpfile );
|
|
|
|
}
|
|
|
|
else if ( REGERR_OK != NR_RegGetEntryString( reg, key, tmpfile, target, sizeof(target) ) )
|
|
|
|
{
|
|
|
|
/* can't read target filename, corruption? */
|
|
|
|
NR_RegDeleteEntry( reg, key, tmpfile );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1999-05-28 01:02:57 +04:00
|
|
|
nsFileSpec targetFile(target);
|
1999-05-07 04:05:54 +04:00
|
|
|
|
1999-03-24 05:16:41 +03:00
|
|
|
targetFile.Delete(PR_FALSE);
|
|
|
|
|
|
|
|
if (!targetFile.Exists())
|
|
|
|
{
|
|
|
|
nsFileSpec parentofTarget;
|
|
|
|
targetFile.GetParent(parentofTarget);
|
|
|
|
|
|
|
|
nsresult result = replaceFile.Move(parentofTarget);
|
|
|
|
if ( NS_SUCCEEDED(result) )
|
|
|
|
{
|
|
|
|
char* leafName = targetFile.GetLeafName();
|
|
|
|
replaceFile.Rename(leafName);
|
1999-04-25 17:27:36 +04:00
|
|
|
nsCRT::free(leafName);
|
1999-03-24 05:16:41 +03:00
|
|
|
|
|
|
|
NR_RegDeleteEntry( reg, key, tmpfile );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* delete list node if empty */
|
|
|
|
if (REGERR_NOMORE == NR_RegEnumEntries(reg, key, &state, tmpfile, sizeof(tmpfile), NULL ))
|
|
|
|
{
|
|
|
|
NR_RegDeleteKey(reg, ROOTKEY_PRIVATE, REG_REPLACE_LIST_KEY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NR_RegClose(reg);
|
|
|
|
}
|
|
|
|
}
|