Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
nsUpdateDriver.cpp File Reference
#include <stdlib.h>
#include <stdio.h>
#include "nsUpdateDriver.h"
#include "nsXULAppAPI.h"
#include "nsAppRunner.h"
#include "nsILocalFile.h"
#include "nsISimpleEnumerator.h"
#include "nsIDirectoryEnumerator.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsString.h"
#include "nsPrintfCString.h"
#include "prproces.h"
#include "prlog.h"

Go to the source code of this file.

Defines

#define LOG(args)   PR_LOG(sUpdateLog, PR_LOG_DEBUG, args)

Functions

static nsresult GetCurrentWorkingDir (char *buf, size_t size)
 ScanDirComparator (nsIFile *a, nsIFile *b, void *unused)
static nsresult ScanDir (nsIFile *dir, nsCOMArray< nsIFile > *result)
static PRBool GetFile (nsIFile *dir, const nsCSubstring &name, nsCOMPtr< nsILocalFile > &result)
static PRBool GetStatusFile (nsIFile *dir, nsCOMPtr< nsILocalFile > &result)
static PRBool IsPending (nsILocalFile *statusFile)
static PRBool SetStatus (nsILocalFile *statusFile, const char *status)
static PRBool CopyUpdaterIntoUpdateDir (nsIFile *appDir, nsIFile *updateDir, nsCOMPtr< nsIFile > &updater)
static void ApplyUpdate (nsIFile *greDir, nsIFile *updateDir, nsILocalFile *statusFile, nsIFile *appDir, int appArgc, char **appArgv)
nsresult ProcessUpdates (nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, int argc, char **argv)

Variables

static const char kUpdaterBin [] = "updater"
static const char kUpdaterINI [] = "updater.ini"

Define Documentation

#define LOG (   args)    PR_LOG(sUpdateLog, PR_LOG_DEBUG, args)

Definition at line 101 of file nsUpdateDriver.cpp.


Function Documentation

static void ApplyUpdate ( nsIFile greDir,
nsIFile updateDir,
nsILocalFile statusFile,
nsIFile appDir,
int  appArgc,
char **  appArgv 
) [static]

Definition at line 328 of file nsUpdateDriver.cpp.

{
  // Steps:
  //  - mark update as 'applying'
  //  - copy updater into update dir
  //  - run updater w/ appDir as the current working dir

  nsCOMPtr<nsIFile> updater;
  if (!CopyUpdaterIntoUpdateDir(greDir, updateDir, updater)) {
    LOG(("failed copying updater\n"));
    return;
  }

  // We need to use the value returned from XRE_GetBinaryPath when attempting
  // to restart the running application.
  nsCOMPtr<nsILocalFile> appFile;

#if defined(MOZ_XULRUNNER) && defined(XP_MACOSX)
  // On OS X we need to pass the location of the xulrunner-stub executable
  // rather than xulrunner-bin. See bug 349737.
  GetXULRunnerStubPath(appArgv[0], getter_AddRefs(appFile));
#else
  XRE_GetBinaryPath(appArgv[0], getter_AddRefs(appFile));
#endif

  if (!appFile)
    return;
  nsCAutoString appFilePath;
  nsresult rv = appFile->GetNativePath(appFilePath);
  if (NS_FAILED(rv))
    return;
  
  nsCAutoString updaterPath;
  rv = updater->GetNativePath(updaterPath);
  if (NS_FAILED(rv))
    return;

  // Get the directory to which the update will be applied. On Mac OSX we need
  // to apply the update to the Foo.app directory which is the parent of the
  // parent of the appDir. On other platforms we will just apply to the appDir.
  nsCAutoString applyToDir;
#if defined(XP_MACOSX)
  {
    nsCOMPtr<nsIFile> parentDir1, parentDir2;
    rv = appDir->GetParent(getter_AddRefs(parentDir1));
    if (NS_FAILED(rv))
      return;
    rv = parentDir1->GetParent(getter_AddRefs(parentDir2));
    if (NS_FAILED(rv))
      return;
    rv = parentDir2->GetNativePath(applyToDir);
  }
#else
  rv = appDir->GetNativePath(applyToDir);
#endif
  if (NS_FAILED(rv))
    return;

  nsCAutoString updateDirPath;
  rv = updateDir->GetNativePath(updateDirPath);
  if (NS_FAILED(rv))
    return;

  // Get the current working directory.
  char workingDirPath[MAXPATHLEN];
  rv = GetCurrentWorkingDir(workingDirPath, sizeof(workingDirPath));
  if (NS_FAILED(rv))
    return;

  if (!SetStatus(statusFile, "applying")) {
    LOG(("failed setting status to 'applying'\n"));
    return;
  }

  // Construct the PID argument for this process.  If we are using execv, then
  // we pass "0" which is then ignored by the updater.
#if defined(USE_EXECV)
  NS_NAMED_LITERAL_CSTRING(pid, "0");
#else
  nsCAutoString pid;
  pid.AppendInt((PRInt32) getpid());
#endif

  int argc = appArgc + 4;
  char **argv = new char*[argc + 1];
  if (!argv)
    return;
  argv[0] = (char*) updaterPath.get();
  argv[1] = (char*) updateDirPath.get();
  argv[2] = (char*) pid.get();
  if (appArgc) {
    argv[3] = workingDirPath;
    argv[4] = (char*) appFilePath.get();
    for (int i = 1; i < appArgc; ++i)
      argv[4 + i] = appArgv[i];
    argv[4 + appArgc] = nsnull;
  } else {
    argv[3] = nsnull;
    argc = 3;
  }

  LOG(("spawning updater process [%s]\n", updaterPath.get()));

#if defined(USE_EXECV)
  chdir(applyToDir.get());
  execv(updaterPath.get(), argv);
#elif defined(XP_WIN)
  _chdir(applyToDir.get());

  if (!WinLaunchChild(updaterPath.get(), appArgc + 4, argv, 1))
    return;
  _exit(0);
#else
  PRStatus status;
  PRProcessAttr *attr;
  
  attr = PR_NewProcessAttr();
  if (!attr)
    goto end;

  status = PR_ProcessAttrSetCurrentDirectory(attr, applyToDir.get());
  if (status != PR_SUCCESS)
    goto end;

#ifdef XP_MACOSX
  SetupMacCommandLine(argc, argv);
#endif

  PR_CreateProcessDetached(updaterPath.get(), argv, nsnull, attr);
  exit(0);

end:
  PR_DestroyProcessAttr(attr); 
  delete[] argv;
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool CopyUpdaterIntoUpdateDir ( nsIFile appDir,
nsIFile updateDir,
nsCOMPtr< nsIFile > &  updater 
) [static]

Definition at line 271 of file nsUpdateDriver.cpp.

{
  // We have to move the updater binary and its resource file.
  const char *filesToMove[] = {
#if defined(XP_MACOSX)
    kUpdaterApp,
#else
    kUpdaterINI,
    kUpdaterBin,
#endif
    nsnull
  };

  nsresult rv;

  for (const char **leafName = filesToMove; *leafName; ++leafName) {
    nsDependentCString leaf(*leafName);
    nsCOMPtr<nsIFile> file;

    // Make sure there is not an existing file in the target location.
    rv = updateDir->Clone(getter_AddRefs(file));
    if (NS_FAILED(rv))
      return PR_FALSE;
    rv = file->AppendNative(leaf);
    if (NS_FAILED(rv))
      return PR_FALSE;
    file->Remove(PR_FALSE);

    // Now, copy into the target location.
    rv = appDir->Clone(getter_AddRefs(file));
    if (NS_FAILED(rv))
      return PR_FALSE;
    rv = file->AppendNative(leaf);
    if (NS_FAILED(rv))
      return PR_FALSE;
    rv = file->CopyToNative(updateDir, EmptyCString());
    if (*leafName != kUpdaterINI && NS_FAILED(rv))
      return PR_FALSE;
  }
  
  // Finally, return the location of the updater binary.
  rv = updateDir->Clone(getter_AddRefs(updater));
  if (NS_FAILED(rv))
    return PR_FALSE;
#if defined(XP_MACOSX)
  rv  = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterApp));
  rv |= updater->AppendNative(NS_LITERAL_CSTRING("Contents"));
  rv |= updater->AppendNative(NS_LITERAL_CSTRING("MacOS"));
  if (NS_FAILED(rv))
    return PR_FALSE;
#endif
  rv = updater->AppendNative(NS_LITERAL_CSTRING(kUpdaterBin));
  return NS_SUCCEEDED(rv); 
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult GetCurrentWorkingDir ( char *  buf,
size_t  size 
) [static]

Definition at line 114 of file nsUpdateDriver.cpp.

{
  // Cannot use NS_GetSpecialDirectory because XPCOM is not yet initialized.
  // This code is duplicated from xpcom/io/SpecialSystemDirectory.cpp:

#if defined(XP_OS2)
  if (DosQueryPathInfo( ".", FIL_QUERYFULLNAME, buf, size))
    return NS_ERROR_FAILURE;
#else
  if(!getcwd(buf, size))
    return NS_ERROR_FAILURE;
#endif
  return NS_OK;
}

Here is the caller graph for this function:

static PRBool GetFile ( nsIFile dir,
const nsCSubstring name,
nsCOMPtr< nsILocalFile > &  result 
) [static]

Definition at line 214 of file nsUpdateDriver.cpp.

{
  nsresult rv;
  
  nsCOMPtr<nsIFile> statusFile;
  rv = dir->Clone(getter_AddRefs(statusFile));
  if (NS_FAILED(rv))
    return PR_FALSE;

  rv = statusFile->AppendNative(name);
  if (NS_FAILED(rv))
    return PR_FALSE;

  result = do_QueryInterface(statusFile, &rv);
  return NS_SUCCEEDED(rv);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool GetStatusFile ( nsIFile dir,
nsCOMPtr< nsILocalFile > &  result 
) [static]

Definition at line 232 of file nsUpdateDriver.cpp.

{
  return GetFile(dir, NS_LITERAL_CSTRING("update.status"), result);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool IsPending ( nsILocalFile statusFile) [static]

Definition at line 238 of file nsUpdateDriver.cpp.

{
  nsresult rv;

  FILE *fp;
  rv = statusFile->OpenANSIFileDesc("r", &fp);
  if (NS_FAILED(rv))
    return PR_FALSE;

  char buf[32];
  char *result = fgets(buf, sizeof(buf), fp);
  fclose(fp);
  if (!result)
    return PR_FALSE;
  
  const char kPending[] = "pending";
  return (strncmp(buf, kPending, sizeof(kPending) - 1) == 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

nsresult ProcessUpdates ( nsIFile greDir,
nsIFile appDir,
nsIFile updRootDir,
int  argc,
char **  argv 
)

Definition at line 467 of file nsUpdateDriver.cpp.

{
  nsresult rv;

  nsCOMPtr<nsIFile> updatesDir;
  rv = updRootDir->Clone(getter_AddRefs(updatesDir));
  if (NS_FAILED(rv))
    return rv;
  rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("updates"));
  if (NS_FAILED(rv))
    return rv;

  PRBool exists;
  rv = updatesDir->Exists(&exists);
  if (NS_FAILED(rv) || !exists)
    return rv;

  nsCOMArray<nsIFile> dirEntries;
  rv = ScanDir(updatesDir, &dirEntries);
  if (NS_FAILED(rv))
    return rv;
  if (dirEntries.Count() == 0)
    return NS_OK;

  // look for the first update subdirectory with a status of pending
  for (int i = 0; i < dirEntries.Count(); ++i) {
    nsCOMPtr<nsILocalFile> statusFile;
    if (GetStatusFile(dirEntries[i], statusFile) && IsPending(statusFile)) {
      ApplyUpdate(greDir, dirEntries[i], statusFile, appDir, argc, argv);
      break;
    }
  }

  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static nsresult ScanDir ( nsIFile dir,
nsCOMArray< nsIFile > *  result 
) [static]

Definition at line 182 of file nsUpdateDriver.cpp.

{
  nsresult rv;

  nsCOMPtr<nsISimpleEnumerator> simpEnum;
  rv = dir->GetDirectoryEntries(getter_AddRefs(simpEnum));
  if (NS_FAILED(rv))
    return rv;

  nsCOMPtr<nsIDirectoryEnumerator> dirEnum = do_QueryInterface(simpEnum, &rv);
  if (NS_FAILED(rv))
    return rv;

  nsCOMPtr<nsIFile> file;
  for (;;) {
    rv = dirEnum->GetNextFile(getter_AddRefs(file));
    if (NS_FAILED(rv))
      return rv;

    // enumeration complete when null file is returned
    if (!file)
      break;

    if (!result->AppendObject(file))
      return NS_ERROR_OUT_OF_MEMORY;
  }

  result->Sort(ScanDirComparator, nsnull);
  return NS_OK;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ScanDirComparator ( nsIFile a,
nsIFile b,
void unused 
)

Definition at line 172 of file nsUpdateDriver.cpp.

{
  // lexically compare the leaf names of these two files
  nsCAutoString a_name, b_name;
  a->GetNativeLeafName(a_name);
  b->GetNativeLeafName(b_name);
  return Compare(a_name, b_name);
}

Here is the call graph for this function:

Here is the caller graph for this function:

static PRBool SetStatus ( nsILocalFile statusFile,
const char *  status 
) [static]

Definition at line 258 of file nsUpdateDriver.cpp.

{
  FILE *fp;
  nsresult rv = statusFile->OpenANSIFileDesc("w", &fp);
  if (NS_FAILED(rv))
    return PR_FALSE;

  fprintf(fp, "%s\n", status);
  fclose(fp);
  return PR_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

const char kUpdaterBin[] = "updater" [static]

Definition at line 106 of file nsUpdateDriver.cpp.

const char kUpdaterINI[] = "updater.ini" [static]

Definition at line 108 of file nsUpdateDriver.cpp.