Back to index

lightning-sunbird  0.9+nobinonly
nsInstallFile.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code, released
00016  * March 31, 1998.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * Netscape Communications Corporation.
00020  * Portions created by the Initial Developer are Copyright (C) 1998
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Daniel Veditz <dveditz@netscape.com>
00025  *   Douglas Turner <dougt@netscape.com>
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 #include "prprf.h"
00042 #include "nsInstallFile.h"
00043 #include "VerReg.h"
00044 #include "ScheduledTasks.h"
00045 #include "nsInstall.h"
00046 #include "nsIDOMInstallVersion.h"
00047 #include "nsInstallResources.h"
00048 #include "nsInstallLogComment.h"
00049 #include "nsInstallBitwise.h"
00050 #include "nsXPIDLString.h"
00051 #include "nsReadableUtils.h"
00052 
00053 /* Public Methods */
00054 
00055 /*     Constructor
00056         inInstall    - softUpdate object we belong to
00057         inComponentName     - full path of the registry component
00058         inVInfo              - full version info
00059         inJarLocation   - location inside the JAR file
00060         inFinalFileSpec     - final       location on disk
00061 */
00062 
00063 MOZ_DECL_CTOR_COUNTER(nsInstallFile)
00064 
00065 nsInstallFile::nsInstallFile(nsInstall* inInstall,
00066                              const nsString& inComponentName,
00067                              const nsString& inVInfo,
00068                              const nsString& inJarLocation,
00069                              nsInstallFolder *folderSpec,
00070                              const nsString& inPartialPath,
00071                              PRInt32 mode,
00072                              PRBool  aRegister,
00073                              PRInt32 *error) 
00074   : nsInstallObject(inInstall),
00075     mVersionInfo(nsnull),
00076     mJarLocation(nsnull),
00077     mExtractedFile(nsnull),
00078     mFinalFile(nsnull),
00079     mVersionRegistryName(nsnull),
00080     mReplaceFile(PR_FALSE),
00081     mRegister(aRegister),
00082     mMode(mode)
00083 {
00084     MOZ_COUNT_CTOR(nsInstallFile);
00085 
00086     PRBool flagExists, flagIsFile;
00087     mFolderCreateCount = 0;
00088 
00089     if ((folderSpec == nsnull) || (inInstall == NULL))
00090     {
00091         *error = nsInstall::INVALID_ARGUMENTS;
00092         return;
00093     }
00094 
00095     *error = nsInstall::SUCCESS;
00096     
00097     nsCOMPtr<nsIFile> tmp = folderSpec->GetFileSpec();
00098     if (!tmp)
00099     {
00100         *error = nsInstall::INVALID_ARGUMENTS;
00101         return;
00102     }
00103 
00104     tmp->Clone(getter_AddRefs(mFinalFile));
00105     if (mFinalFile == nsnull)
00106     {
00107         *error = nsInstall::OUT_OF_MEMORY;
00108         return;
00109     }
00110 
00111     mFinalFile->Exists(&flagExists);
00112     if (flagExists)
00113     {
00114         // is there a file with the same name as the proposed folder?
00115         mFinalFile->IsFile(&flagIsFile);
00116         if ( flagIsFile) 
00117         {
00118             *error = nsInstall::ACCESS_DENIED;
00119             return;
00120         }
00121         // else this directory already exists, so do nothing
00122     }
00123 
00124     //Need to parse the inPartialPath to remove any separators
00125     PRBool finished = PR_FALSE;
00126     PRUint32 offset = 0;
00127     PRInt32 location = 0, nodeLength = 0;
00128     nsString subString;
00129 
00130     location = inPartialPath.FindChar('/', offset);
00131     if (location == ((PRInt32)inPartialPath.Length() - 1)) //trailing slash
00132     {
00133         *error = nsInstall::INVALID_ARGUMENTS;
00134         return;
00135     }
00136 
00137     while (!finished)
00138     {
00139         if (location == kNotFound) //no separators were found
00140         {
00141             nodeLength = inPartialPath.Length() - offset;
00142             finished = PR_TRUE;
00143         }
00144         else
00145         {
00146             nodeLength = location - offset;
00147         }
00148         
00149         if (nodeLength > MAX_FILENAME) 
00150         {
00151             *error = nsInstall::FILENAME_TOO_LONG;
00152             return;
00153         }
00154         else
00155         {
00156             nsresult rv = inPartialPath.Mid(subString, offset, nodeLength);
00157             mFinalFile->Append(subString);
00158             offset += nodeLength + 1;
00159             if (!finished)
00160                 location = inPartialPath.FindChar('/', offset);
00161         }
00162     }
00163 
00164     mFinalFile->Exists(&mReplaceFile);
00165     mVersionRegistryName  = new nsString(inComponentName);
00166     mJarLocation          = new nsString(inJarLocation);
00167     mVersionInfo             = new nsString(inVInfo);
00168      
00169     if (mVersionRegistryName == nsnull ||
00170         mJarLocation         == nsnull ||
00171         mVersionInfo         == nsnull )
00172     {
00173         *error = nsInstall::OUT_OF_MEMORY;
00174         return;
00175     }
00176 }
00177 
00178 
00179 nsInstallFile::~nsInstallFile()
00180 {
00181     if (mVersionRegistryName)
00182         delete mVersionRegistryName;
00183   
00184     if (mJarLocation)
00185         delete mJarLocation;
00186   
00187     if (mVersionInfo)
00188         delete mVersionInfo;
00189     
00190     //if(mFinalFile)
00191     //    mFinalFile = nsnull;
00192 
00193     //if(mExtractedFile)
00194     //    mExtractedFile = nsnull;
00195 
00196     MOZ_COUNT_DTOR(nsInstallFile);
00197 }
00198 
00199 
00200 
00201 
00202 void nsInstallFile::CreateAllFolders(nsInstall *aInstall, nsIFile *aFolder, PRInt32 *aError)
00203 {
00204     PRBool              flagExists;
00205     nsInstallLogComment *ilc   = nsnull;
00206 
00207     nsresult rv = aFolder->Exists(&flagExists);
00208     if (NS_FAILED(rv))
00209         *aError = nsInstall::UNEXPECTED_ERROR;
00210     else if (flagExists)
00211         *aError = nsInstall::SUCCESS;
00212     else
00213     {
00214         // Doesn't exist, work our way up trying to create each node above
00215         nsCOMPtr<nsIFile> parent;
00216         rv = aFolder->GetParent(getter_AddRefs(parent));
00217         if (NS_FAILED(rv))
00218         {
00219             // we're already at the top -- give up
00220             *aError = nsInstall::ACCESS_DENIED;
00221             return;
00222         }
00223 
00224         CreateAllFolders(aInstall, parent, aError);
00225         if (*aError != nsInstall::SUCCESS)
00226             return;
00227 
00228         aFolder->Create(nsIFile::DIRECTORY_TYPE, 0755); //nsIFileXXX: What kind of permissions are required here?
00229         ++mFolderCreateCount;
00230 
00231         nsAutoString folderPath;
00232         aFolder->GetPath(folderPath);
00233         ilc = new nsInstallLogComment(aInstall,
00234                                       NS_LITERAL_STRING("CreateFolder"),
00235                                       folderPath,
00236                                       aError);
00237         if(ilc == nsnull)
00238             *aError = nsInstall::OUT_OF_MEMORY;
00239 
00240         if(*aError == nsInstall::SUCCESS)
00241             *aError = mInstall->ScheduleForInstall(ilc);
00242     }
00243 }
00244 
00245 #ifdef XXX_SSU
00246 void nsInstallFile::RemoveAllFolders()
00247 {
00248     /* the nsFileSpecMac.cpp operator += requires "this" (the nsFileSpec)
00249      * to be an existing dir
00250      */
00251 
00252     PRUint32   i;
00253     nsFileSpec nsfsFolder;
00254     nsFileSpec nsfsParentFolder;
00255     nsString   nsStrFolder;
00256 
00257     if(mFinalFile != nsnull)
00258     {
00259       mFinalFile->GetParent(nsfsFolder);
00260       for(i = 0; i < mFolderCreateCount; i++)
00261       {
00262           nsfsFolder.Remove(PR_FALSE);
00263           nsfsFolder.GetParent(nsfsParentFolder);
00264           nsfsFolder = nsfsParentFolder;
00265       }
00266     }
00267 }
00268 #endif
00269 
00270 
00271 
00272 
00273 
00274 
00275 /* Prepare
00276  * Extracts file out of the JAR archive
00277  */
00278 PRInt32 nsInstallFile::Prepare()
00279 {
00280     PRInt32 error = nsInstall::SUCCESS;
00281 
00282     if (mInstall == nsnull || mFinalFile == nsnull || mJarLocation == nsnull )
00283         return nsInstall::INVALID_ARGUMENTS;
00284 
00285     if (mReplaceFile == PR_FALSE)
00286     {
00287        /* although it appears that we are creating the dir _again_ it is necessary
00288         * when inPartialPath has arbitrary levels of nested dirs before the leaf
00289         */
00290         nsCOMPtr<nsIFile> parent;
00291         mFinalFile->GetParent(getter_AddRefs(parent));
00292         CreateAllFolders(mInstall, parent, &error);
00293         if(nsInstall::SUCCESS != error)
00294             return error;
00295     }
00296 
00297     return mInstall->ExtractFileFromJar(*mJarLocation, mFinalFile, getter_AddRefs(mExtractedFile)); 
00298 }
00299 
00300 /* Complete
00301  * Completes the install:
00302  * - move the downloaded file to the final location
00303  * - updates the registry
00304  */
00305 PRInt32 nsInstallFile::Complete()
00306 {
00307     PRInt32 err;
00308 
00309     if (mInstall == nsnull || mVersionRegistryName == nsnull || mFinalFile == nsnull ) 
00310     {
00311        return nsInstall::INVALID_ARGUMENTS;
00312     }
00313    
00314     err = CompleteFileMove();
00315     
00316     if ( mRegister && (0 == err || nsInstall::REBOOT_NEEDED == err) ) 
00317     {
00318         nsCAutoString path;
00319         mFinalFile->GetNativePath(path);
00320         VR_Install( NS_CONST_CAST(char*, NS_ConvertUCS2toUTF8(*mVersionRegistryName).get()),
00321                     NS_CONST_CAST(char*, path.get()),
00322                     NS_CONST_CAST(char*, NS_ConvertUCS2toUTF8(*mVersionInfo).get()),
00323                     PR_FALSE );
00324     }
00325     
00326     return err;
00327 
00328 }
00329 
00330 void nsInstallFile::Abort()
00331 {
00332     if (mExtractedFile != nsnull)
00333         mExtractedFile->Remove(PR_FALSE);
00334 }
00335 
00336 #define RESBUFSIZE 4096
00337 char* nsInstallFile::toString()
00338 {
00339     char* buffer  = new char[RESBUFSIZE];
00340     char* rsrcVal = nsnull;
00341 
00342     if (buffer == nsnull || !mInstall)
00343         return nsnull;
00344     else
00345         buffer[0] = '\0';
00346     
00347     if (mReplaceFile)
00348     {
00349         if(mMode & WIN_SHARED_FILE)
00350         {
00351             rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("ReplaceSharedFile"));
00352         }
00353         else
00354         {
00355             rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("ReplaceFile"));
00356         }
00357     }
00358     else
00359     {
00360         if(mMode & WIN_SHARED_FILE)
00361         {
00362             rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("InstallSharedFile"));
00363         }
00364         else
00365         {
00366             rsrcVal = mInstall->GetResourcedString(NS_LITERAL_STRING("InstallFile"));
00367         }
00368     }
00369 
00370     if (rsrcVal)
00371     {
00372         char*    interimCStr = nsnull;
00373         nsString interimStr;
00374 
00375         if(mMode & DO_NOT_UNINSTALL)
00376           interimStr.Assign(NS_LITERAL_STRING("(*dnu*) "));
00377 
00378         interimStr.AppendWithConversion(rsrcVal);
00379         interimCStr = ToNewCString(interimStr);
00380 
00381         if(interimCStr)
00382         {
00383             nsCAutoString fname;
00384             if (mFinalFile)
00385                 mFinalFile->GetNativePath(fname);
00386 
00387             PR_snprintf( buffer, RESBUFSIZE, interimCStr, fname.get() );
00388             Recycle(interimCStr);
00389         }
00390         Recycle(rsrcVal);
00391     }
00392 
00393     return buffer;
00394 }
00395 
00396 
00397 PRInt32 nsInstallFile::CompleteFileMove()
00398 {
00399     int    result         = 0;
00400     PRBool bIsEqual = PR_FALSE;
00401     
00402     if (mExtractedFile == nsnull) 
00403     {
00404         return nsInstall::UNEXPECTED_ERROR;
00405     }
00406        
00407     
00408     mExtractedFile->Equals(mFinalFile, &bIsEqual);
00409     if ( bIsEqual ) 
00410     {
00411         /* No need to rename, they are the same */
00412         result = nsInstall::SUCCESS;
00413     } 
00414     else 
00415     {
00416         result = ReplaceFileNowOrSchedule(mExtractedFile, mFinalFile, mMode );
00417     }
00418 
00419     if(mMode & WIN_SHARED_FILE)
00420     {
00421       nsCAutoString path;
00422       mFinalFile->GetNativePath(path);
00423       RegisterSharedFile(path.get(), mReplaceFile);
00424     }
00425 
00426     return result;  
00427 }
00428 
00429 /* CanUninstall
00430 * InstallFile() installs files which can be uninstalled,
00431 * hence this function returns true. 
00432 */
00433 PRBool
00434 nsInstallFile::CanUninstall()
00435 {
00436     return PR_TRUE;
00437 }
00438 
00439 /* RegisterPackageNode
00440 * InstallFile() installs files which need to be registered,
00441 * hence this function returns true.
00442 */
00443 PRBool
00444 nsInstallFile::RegisterPackageNode()
00445 {
00446     return PR_TRUE;
00447 }
00448