예제 #1
0
        /// <summary>
        /// Starts the updater executable and sends update data to it
        /// </summary>
        /// <param name="relaunchApplication">true if relaunching the caller application is required; false otherwise</param>
        /// <returns>True if successful (unless a restart was required</returns>
        public bool ApplyUpdates(bool relaunchApplication)
        {
            lock (UpdatesToApply)
            {
                LatestError = null;

                // Make sure the current backup folder is accessible for writing from this process
                if (!Utils.PermissionsCheck.HaveWritePermissionsForFolder(BackupFolder))
                {
                    _BackupFolder = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                        UpdateProcessName + "UpdateBackups");
                }
                else
                {
                    // Remove old backup folder, in case this same folder was used previously,
                    // and it wasn't removed for some reason
                    if (Directory.Exists(BackupFolder))
                    {
                        Directory.Delete(BackupFolder, true);
                    }
                }
                Directory.CreateDirectory(BackupFolder);

                var executeOnAppRestart = new Dictionary <string, object>();
                State = UpdateProcessState.RollbackRequired;
                foreach (var task in UpdatesToApply)
                {
                    // First, execute the task
                    if (!task.Execute())
                    {
                        // TODO: notify about task execution failure using exceptions
                        continue;
                    }

                    // Add any pending cold updates to the list
                    var en = task.GetColdUpdates();
                    while (en.MoveNext())
                    {
                        // Last write wins
                        executeOnAppRestart[en.Current.Key] = en.Current.Value;
                    }
                }

                // If an application restart is required
                if (executeOnAppRestart.Count > 0)
                {
                    // Add some environment variables to the dictionary object which will be passed to the updater
                    executeOnAppRestart["ENV:AppPath"]             = ApplicationPath;
                    executeOnAppRestart["ENV:WorkingDirectory"]    = Environment.CurrentDirectory;
                    executeOnAppRestart["ENV:TempFolder"]          = TempFolder;
                    executeOnAppRestart["ENV:BackupFolder"]        = BackupFolder;
                    executeOnAppRestart["ENV:RelaunchApplication"] = relaunchApplication;

                    // Naming it updater.exe seem to trigger the UAC, and we don't want that
                    var  updStarter = new UpdateStarter(Path.Combine(TempFolder, "foo.exe"), executeOnAppRestart, UpdateProcessName);
                    bool createdNew;
                    using (var _ = new Mutex(true, UpdateProcessName, out createdNew))
                    {
                        if (!updStarter.Start())
                        {
                            return(false);
                        }

                        Environment.Exit(0);
                    }
                }

                State = UpdateProcessState.AppliedSuccessfully;
                UpdatesToApply.Clear();
            }

            return(true);
        }
예제 #2
0
        /// <summary>
        /// Starts the updater executable and sends update data to it
        /// </summary>
        /// <param name="relaunchApplication">true if relaunching the caller application is required; false otherwise</param>
        /// <returns>True if successful (unless a restart was required</returns>
        public bool ApplyUpdates(bool relaunchApplication)
        {
            lock (UpdatesToApply)
            {
                LatestError = null;
                bool revertToDefaultBackupPath = true;

                // Make sure the current backup folder is accessible for writing from this process
                string backupParentPath = Path.GetDirectoryName(BackupFolder) ?? string.Empty;
                if (Directory.Exists(backupParentPath) && Utils.PermissionsCheck.HaveWritePermissionsForFolder(backupParentPath))
                {
                    // Remove old backup folder, in case this same folder was used previously,
                    // and it wasn't removed for some reason
                    try
                    {
                        if (Directory.Exists(BackupFolder))
                            Directory.Delete(BackupFolder, true);
                        revertToDefaultBackupPath = false;
                    }
                    catch (UnauthorizedAccessException)
                    {
                    }

                    // Attempt to (re-)create the backup folder
                    try
                    {
                        Directory.CreateDirectory(BackupFolder);

                        if (!Utils.PermissionsCheck.HaveWritePermissionsForFolder(BackupFolder))
                            revertToDefaultBackupPath = true;
                    }
                    catch (UnauthorizedAccessException)
                    {
                        // We're having permissions issues with this folder, so we'll attempt
                        // using a backup in a default location
                        revertToDefaultBackupPath = true;
                    }
                }

                if (revertToDefaultBackupPath)
                {
                    _backupFolder = Path.Combine(
                        Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                        UpdateProcessName + "UpdateBackups");

                    try
                    {
                        Directory.CreateDirectory(BackupFolder);
                    }
                    catch (UnauthorizedAccessException ex)
                    {
                        // We can't backup, so we abort
                        LatestError = ex.ToString();
                        return false;
                    }
                }

                var executeOnAppRestart = new Dictionary<string, object>();
                State = UpdateProcessState.RollbackRequired;
                foreach (var task in UpdatesToApply)
                {
                    // First, execute the task
                    if (!task.Execute())
                    {
                        // TODO: notify about task execution failure using exceptions
                        continue;
                    }

                    // Add any pending cold updates to the list
                    var en = task.GetColdUpdates();
                    while (en.MoveNext())
                    {
                        // Last write wins
                        executeOnAppRestart[en.Current.Key] = en.Current.Value;
                    }
                }

                // If an application restart is required
                if (executeOnAppRestart.Count > 0)
                {
                    // Add some environment variables to the dictionary object which will be passed to the updater
                    executeOnAppRestart["ENV:AppPath"] = ApplicationPath;
                    executeOnAppRestart["ENV:WorkingDirectory"] = Environment.CurrentDirectory;
                    executeOnAppRestart["ENV:TempFolder"] = TempFolder;
                    executeOnAppRestart["ENV:BackupFolder"] = BackupFolder;
                    executeOnAppRestart["ENV:RelaunchApplication"] = relaunchApplication;

                    if (!Directory.Exists(TempFolder))
                        Directory.CreateDirectory(TempFolder);

                    // Naming it updater.exe seem to trigger the UAC, and we don't want that
                    var updStarter = new UpdateStarter(Path.Combine(TempFolder, "foo.exe"), executeOnAppRestart, UpdateProcessName);
                    bool createdNew;
                    using (var _ = new Mutex(true, UpdateProcessName, out createdNew))
                    {
                        if (!updStarter.Start())
                            return false;

                        Environment.Exit(0);
                    }
                }

                State = UpdateProcessState.AppliedSuccessfully;
                UpdatesToApply.Clear();
            }

            return true;
        }
예제 #3
0
        /// <summary>
        /// Starts the updater executable and sends update data to it
        /// </summary>
        /// <param name="RestartApplication">true if relaunching the caller application is required; false otherwise</param>
        /// <returns>True if successful (unless a restart was required</returns>
        public bool ApplyUpdates(bool RelaunchApplication)
        {
            lock (UpdatesToApply)
            {
                // Make sure the current backup folder is accessible for writing from this process
                if (!Utils.PermissionsCheck.HaveWritePermissionsForFolder(BackupFolder))
                {
                    _BackupFolder = Path.Combine(
                             Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                             UpdateProcessName + "UpdateBackups");
                }
                else
                {
                    // Remove old backup folder, in case this same folder was used previously,
                    // and it wasn't removed for some reason
                    if (Directory.Exists(BackupFolder))
                        Directory.Delete(BackupFolder, true);
                }
                Directory.CreateDirectory(BackupFolder);

                Dictionary<string, object> executeOnAppRestart = new Dictionary<string, object>();
                State = UpdateProcessState.RollbackRequired;
                foreach (IUpdateTask task in UpdatesToApply)
                {
                    if (!task.Execute())
                    {
                        // TODO: notify about task execution failure using exceptions
                    }

                    // This is the only place where we have non-generalized code in UpdateManager.
                    // The reason for that is the updater currently only supports replacing bytes by path, which
                    // only FileUpdaterTask does - so there's no reason to generalize this portion too.
                    else if (task is FileUpdateTask && task.Attributes.ContainsKey("localPath"))
                    {
                        if (!task.Attributes.ContainsKey("apply") ||
                            (task.Attributes.ContainsKey("apply") && "app-restart".Equals(task.Attributes["apply"])))
                        {
                            FileUpdateTask fut = (FileUpdateTask)task;
                            executeOnAppRestart[task.Attributes["localPath"]] = fut.tempFile;
                        }
                    }
                }

                // If an application restart is required
                if (executeOnAppRestart.Count > 0)
                {
                    // Add some environment variables to the dictionary object which will be passed to the updater
                    executeOnAppRestart["ENV:AppPath"] = ApplicationPath;
                    executeOnAppRestart["ENV:TempFolder"] = TempFolder;
                    executeOnAppRestart["ENV:BackupFolder"] = BackupFolder;
                    executeOnAppRestart["ENV:RelaunchApplication"] = RelaunchApplication;

                    UpdateStarter updStarter = new UpdateStarter(Path.Combine(TempFolder, "updater.exe"), executeOnAppRestart, UpdateProcessName);
                    bool createdNew;
                    using (Mutex mutex = new Mutex(true, UpdateProcessName, out createdNew))
                    {
                        if (!updStarter.Start())
                            return false;

                        Environment.Exit(0);
                    }
                }

                State = UpdateProcessState.AppliedSuccessfully;
                UpdatesToApply.Clear();
            }

            return true;
        }