Mozilla/mozilla/xpinstall/src/nsInstallFile.cpp
ssu%netscape.com 7f30e74836 added bit field in nsInstallFile for Windows Shared File and Do No Uninstall.
added support in fileop for registering ole server files.

changed the way logging is done in install.log to write to the log file *before* the attempt to complete() the file installation process.  This helps with debugging because is shows what file the installation probably stopped on.


git-svn-id: svn://10.0.0.236/trunk@69622 18797224-902f-48f8-a5cc-f745e15eee43
2000-05-14 03:07:05 +00:00

609 lines
17 KiB
C++

/* -*- 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.1 (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.
*
* Contributor(s):
* Daniel Veditz <dveditz@netscape.com>
* Douglas Turner <dougt@netscape.com>
*/
#include "prprf.h"
#include "nsInstallFile.h"
#include "nsFileSpec.h"
#include "VerReg.h"
#include "ScheduledTasks.h"
#include "nsInstall.h"
#include "nsIDOMInstallVersion.h"
#include "nsInstallResources.h"
#include "nsInstallLogComment.h"
#include "nsInstallBitwise.h"
/* Public Methods */
/* Constructor
inInstall - softUpdate object we belong to
inComponentName - full path of the registry component
inVInfo - full version info
inJarLocation - location inside the JAR file
inFinalFileSpec - final location on disk
*/
MOZ_DECL_CTOR_COUNTER(nsInstallFile);
nsInstallFile::nsInstallFile(nsInstall* inInstall,
const nsString& inComponentName,
const nsString& inVInfo,
const nsString& inJarLocation,
nsInstallFolder *folderSpec,
const nsString& inPartialPath,
PRInt32 mode,
PRInt32 *error)
: nsInstallObject(inInstall),
mVersionInfo(nsnull),
mJarLocation(nsnull),
mExtractedFile(nsnull),
mFinalFile(nsnull),
mVersionRegistryName(nsnull),
mReplaceFile(PR_FALSE),
mChildFile(PR_TRUE),
mUpgradeFile(PR_FALSE),
mSkipInstall(PR_FALSE),
mMode(mode)
{
MOZ_COUNT_CTOR(nsInstallFile);
PRBool flagExists, flagIsFile;
mFolderCreateCount = 0;
if ((folderSpec == nsnull) || (inInstall == NULL))
{
*error = nsInstall::INVALID_ARGUMENTS;
return;
}
*error = nsInstall::SUCCESS;
/* Check for existence of the newer version */
#if 0 // XXX need to re-implement force mode in the opposite sense
char* qualifiedRegNameString = inComponentName.ToNewCString();
// --------------------------------------------------------------------
// we always install if forceInstall is true, or the new file's
// version is null, or the file doesn't previously exist.
//
// IFF it's not force, AND the new file has a version, AND it's been
// previously installed, THEN we have to do the version comparing foo.
// --------------------------------------------------------------------
if ( !(mode & INSTALL_NO_COMPARE ) && (inVInfo != "") &&
( VR_ValidateComponent( qualifiedRegNameString ) == 0 ) )
{
nsInstallVersion *newVersion = new nsInstallVersion();
if (newVersion == nsnull)
{
Recycle(qualifiedRegNameString);
*error = nsInstall::OUT_OF_MEMORY;
return;
}
newVersion->Init(inVInfo);
VERSION versionStruct;
VR_GetVersion( qualifiedRegNameString, &versionStruct );
nsInstallVersion* oldVersion = new nsInstallVersion();
if (oldVersion == nsnull)
{
Recycle(qualifiedRegNameString);
delete oldVersion;
*error = nsInstall::OUT_OF_MEMORY;
return;
}
oldVersion->Init(versionStruct.major,
versionStruct.minor,
versionStruct.release,
versionStruct.build);
PRInt32 areTheyEqual;
newVersion->CompareTo(oldVersion, &areTheyEqual);
delete oldVersion;
delete newVersion;
if ( areTheyEqual < 0 )
{
// the file to be installed is OLDER than what is on disk.
// Don't install it.
mSkipInstall = PR_TRUE;
}
}
Recycle(qualifiedRegNameString);
#endif
nsCOMPtr<nsIFile> tmp = folderSpec->GetFileSpec();
if (!tmp)
{
*error = nsInstall::INVALID_ARGUMENTS;
return;
}
tmp->Clone(getter_AddRefs(mFinalFile));
if (mFinalFile == nsnull)
{
*error = nsInstall::OUT_OF_MEMORY;
return;
}
mFinalFile->Exists(&flagExists);
if (flagExists)
{
// is there a file with the same name as the proposed folder?
mFinalFile->IsFile(&flagIsFile);
if ( flagIsFile)
{
*error = nsInstall::FILENAME_ALREADY_USED;
return;
}
// else this directory already exists, so do nothing
}
//Need to parse the inPartialPath to remove any separators
PRBool finished = PR_FALSE;
PRUint32 offset = 0;
PRInt32 location = 0, pass = 0;
nsString subString;
//nsString tempPartialPath(inPartialPath);
while (!finished)
{
location = inPartialPath.FindChar('/',PR_FALSE, offset);
if ((location < 0) && (pass == 0)) //no separators were found
{
nsAutoCString tempPartialPath(inPartialPath);
mFinalFile->Append(tempPartialPath);
finished = PR_TRUE;
}
else if ((location < 0) && (pass > 0) && (offset < inPartialPath.mLength)) //last occurance
{
nsresult rv = inPartialPath.Mid(subString, offset, inPartialPath.mLength-offset);
nsAutoCString tempSubString(subString);
mFinalFile->Append(tempSubString);
finished = PR_TRUE;
}
else
{
nsresult rv = inPartialPath.Mid(subString, offset, location-offset);
nsAutoCString tempSubString(subString);
mFinalFile->Append(tempSubString);
offset = location + 1;
pass++;
}
}
//{
// nsresult rv = mFinalFile->Append(inPartialPath.ToNewCString());
// if (rv != NS_OK)
// {
// *error = nsInstall::ILLEGAL_RELATIVE_PATH;
// return;
// }
//}
mFinalFile->Exists(&mReplaceFile);
mVersionRegistryName = new nsString(inComponentName);
mJarLocation = new nsString(inJarLocation);
mVersionInfo = new nsString(inVInfo);
if (mVersionRegistryName == nsnull ||
mJarLocation == nsnull ||
mVersionInfo == nsnull )
{
*error = nsInstall::OUT_OF_MEMORY;
return;
}
nsString regPackageName;
mInstall->GetRegPackageName(regPackageName);
// determine Child status
if ( regPackageName.IsEmpty() )
{
// in the "current communicator package" absolute pathnames (start
// with slash) indicate shared files -- all others are children
mChildFile = ( mVersionRegistryName->CharAt(0) != '/' );
}
else
{
mChildFile = mVersionRegistryName->EqualsWithConversion( regPackageName,
PR_FALSE,
regPackageName.Length() );
}
}
nsInstallFile::~nsInstallFile()
{
if (mVersionRegistryName)
delete mVersionRegistryName;
if (mJarLocation)
delete mJarLocation;
if (mVersionInfo)
delete mVersionInfo;
//if(mFinalFile)
// mFinalFile = nsnull;
//if(mExtractedFile)
// mExtractedFile = nsnull;
MOZ_COUNT_DTOR(nsInstallFile);
}
void nsInstallFile::CreateAllFolders(nsInstall *inInstall, nsIFile *inFolderPath, PRInt32 *error)
{
/* the nsFileSpecMac.cpp operator += requires "this" (the nsFileSpec)
* to be an existing dir
*/
nsCOMPtr<nsIFile> nsfsFolderPath;
nsString nsStrFolder;
PRBool flagExists;
int result = 0;
nsInstallLogComment *ilc = nsnull;
inFolderPath->Exists(&flagExists);
if(!flagExists)
{
char *szPath = nsnull;
inFolderPath->GetParent(getter_AddRefs(nsfsFolderPath));
CreateAllFolders(inInstall, nsfsFolderPath, error);
inFolderPath->Create(nsIFile::DIRECTORY_TYPE, 0755); //nsIFileXXX: What kind of permissions are required here?
++mFolderCreateCount;
inFolderPath->GetPath(&szPath);
nsStrFolder.AssignWithConversion(szPath);
nsAllocator::Free(szPath);
ilc = new nsInstallLogComment(inInstall, NS_ConvertASCIItoUCS2("CreateFolder"), nsStrFolder, error);
if(ilc == nsnull)
*error = nsInstall::OUT_OF_MEMORY;
if(*error == nsInstall::SUCCESS)
*error = mInstall->ScheduleForInstall(ilc);
}
}
#ifdef XXX_SSU
void nsInstallFile::RemoveAllFolders()
{
/* the nsFileSpecMac.cpp operator += requires "this" (the nsFileSpec)
* to be an existing dir
*/
PRUint32 i;
nsFileSpec nsfsFolder;
nsFileSpec nsfsParentFolder;
nsString nsStrFolder;
if(mFinalFile != nsnull)
{
mFinalFile->GetParent(nsfsFolder);
for(i = 0; i < mFolderCreateCount; i++)
{
nsfsFolder.Delete(PR_FALSE);
nsfsFolder.GetParent(nsfsParentFolder);
nsfsFolder = nsfsParentFolder;
}
}
}
#endif
/* Prepare
* Extracts file out of the JAR archive
*/
PRInt32 nsInstallFile::Prepare()
{
PRInt32 error = nsInstall::SUCCESS;
if (mSkipInstall)
return nsInstall::SUCCESS;
if (mInstall == nsnull || mFinalFile == nsnull || mJarLocation == nsnull )
return nsInstall::INVALID_ARGUMENTS;
if (mReplaceFile == PR_FALSE)
{
/* although it appears that we are creating the dir _again_ it is necessary
* when inPartialPath has arbitrary levels of nested dirs before the leaf
*/
nsCOMPtr<nsIFile> parent;
mFinalFile->GetParent(getter_AddRefs(parent));
CreateAllFolders(mInstall, parent, &error);
if(nsInstall::SUCCESS != error)
return error;
}
return mInstall->ExtractFileFromJar(*mJarLocation, mFinalFile, getter_AddRefs(mExtractedFile));
}
/* Complete
* Completes the install:
* - move the downloaded file to the final location
* - updates the registry
*/
PRInt32 nsInstallFile::Complete()
{
PRInt32 err;
if (mInstall == nsnull || mVersionRegistryName == nsnull || mFinalFile == nsnull )
{
return nsInstall::INVALID_ARGUMENTS;
}
if (mSkipInstall)
return nsInstall::SUCCESS;
err = CompleteFileMove();
if ( 0 == err || nsInstall::REBOOT_NEEDED == err )
{
// XXX Don't register individual files for now -- crucial performance
// speed up on the Mac, and we'll switch uninstall schemes after beta
// RegisterInVersionRegistry();
}
return err;
}
void nsInstallFile::Abort()
{
if (mExtractedFile != nsnull)
mExtractedFile->Delete(PR_FALSE);
}
#define RESBUFSIZE 4096
char* nsInstallFile::toString()
{
char* buffer = new char[RESBUFSIZE];
char* rsrcVal = nsnull;
char* fname = nsnull;
if (buffer == nsnull || !mInstall)
return nsnull;
else
buffer[0] = '\0';
if (mReplaceFile)
{
if(mMode & nsInstall::WIN_SHARED_FILE)
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("ReplaceSharedFile"));
}
else
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("ReplaceFile"));
}
}
else if (mSkipInstall)
{
if(mMode & nsInstall::WIN_SHARED_FILE)
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("SkipSharedFile"));
}
else
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("SkipFile"));
}
}
else
{
if(mMode & nsInstall::WIN_SHARED_FILE)
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("InstallSharedFile"));
}
else
{
rsrcVal = mInstall->GetResourcedString(NS_ConvertASCIItoUCS2("InstallFile"));
}
}
if (rsrcVal)
{
char* interimCStr = nsnull;
nsString interimStr;
if(mMode & nsInstall::DO_NOT_UNINSTALL)
interimStr.AssignWithConversion("(*dnu*) ");
interimStr.AppendWithConversion(rsrcVal);
interimCStr = interimStr.ToNewCString();
if(interimCStr == nsnull)
return interimCStr;
if (mFinalFile)
mFinalFile->GetPath(&fname);
PR_snprintf( buffer, RESBUFSIZE, interimCStr, fname );
Recycle(rsrcVal);
}
return buffer;
}
PRInt32 nsInstallFile::CompleteFileMove()
{
int result = 0;
char *temp;
PRBool bAlreadyExists = PR_FALSE;
if (mExtractedFile == nsnull)
{
return nsInstall::UNEXPECTED_ERROR;
}
if ( mExtractedFile == mFinalFile )
{
/* No need to rename, they are the same */
result = nsInstall::SUCCESS;
}
else
{
result = ReplaceFileNowOrSchedule(mExtractedFile, mFinalFile );
}
if(mMode & nsInstall::WIN_SHARED_FILE)
{
if(mReplaceFile || mSkipInstall)
bAlreadyExists = PR_TRUE;
mFinalFile->GetPath(&temp);
RegisterSharedFile(temp, bAlreadyExists);
}
return result;
}
PRInt32
nsInstallFile::RegisterInVersionRegistry()
{
int refCount;
nsString regPackageName;
mInstall->GetRegPackageName(regPackageName);
// Register file and log for Uninstall
if (!mChildFile)
{
int found;
if (!regPackageName.IsEmpty())
{
found = VR_UninstallFileExistsInList( (char*)(const char*)nsAutoCString(regPackageName) ,
(char*)(const char*)nsAutoCString(*mVersionRegistryName));
}
else
{
found = VR_UninstallFileExistsInList( "", (char*)(const char*)nsAutoCString(*mVersionRegistryName) );
}
if (found != REGERR_OK)
mUpgradeFile = PR_FALSE;
else
mUpgradeFile = PR_TRUE;
}
else if (REGERR_OK == VR_InRegistry( (char*)(const char*)nsAutoCString(*mVersionRegistryName)))
{
mUpgradeFile = PR_TRUE;
}
else
{
mUpgradeFile = PR_FALSE;
}
if ( REGERR_OK != VR_GetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), &refCount ))
{
refCount = 0;
}
char* temp;
mFinalFile->GetPath(&temp);
VR_Install( (char*)(const char*)nsAutoCString(*mVersionRegistryName),
(char*)(const char*)temp, // DO NOT CHANGE THIS.
(char*)(const char*)nsAutoCString(*mVersionInfo),
PR_FALSE );
if (mUpgradeFile)
{
if (refCount == 0)
VR_SetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), 1 );
else
VR_SetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), refCount ); //FIX?? what should the ref count be/
}
else
{
if (refCount != 0)
{
VR_SetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), refCount + 1 );
}
else
{
if (mReplaceFile)
VR_SetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), 2 );
else
VR_SetRefCount( (char*)(const char*)nsAutoCString(*mVersionRegistryName), 1 );
}
}
if ( !mChildFile && !mUpgradeFile )
{
if (!regPackageName.IsEmpty())
{
VR_UninstallAddFileToList( (char*)(const char*)nsAutoCString(regPackageName),
(char*)(const char*)nsAutoCString(*mVersionRegistryName));
}
else
{
VR_UninstallAddFileToList( "", (char*)(const char*)nsAutoCString(*mVersionRegistryName) );
}
}
return nsInstall::SUCCESS;
}
/* CanUninstall
* InstallFile() installs files which can be uninstalled,
* hence this function returns true.
*/
PRBool
nsInstallFile::CanUninstall()
{
return PR_TRUE;
}
/* RegisterPackageNode
* InstallFile() installs files which need to be registered,
* hence this function returns true.
*/
PRBool
nsInstallFile::RegisterPackageNode()
{
return PR_TRUE;
}