示例#1
0
        /// <summary>
        /// Delete the temp folder as a whole and fail silently
        /// </summary>
        public void CleanUp()
        {
            Abort(true);

            lock (UpdatesToApply)
            {
                UpdatesToApply.Clear();
                State = UpdateProcessState.NotChecked;

                try
                {
                    if (Directory.Exists(Config.TempFolder))
                    {
                        FileSystem.DeleteDirectory(Config.TempFolder);
                    }
                }
                catch { }

                try
                {
                    if (Directory.Exists(Config.BackupFolder))
                    {
                        FileSystem.DeleteDirectory(Config.BackupFolder);
                    }
                }
                catch { }

                ShouldStop = false;
            }
        }
示例#2
0
        /// <summary>
        /// Check for updates synchronouly
        /// </summary>
        /// <param name="source">Updates source to use</param>
        /// <param name="callback">Callback function to call when done</param>
        /// <returns>true if successful and updates exist</returns>
        private bool CheckForUpdates(IUpdateSource source, Action <int> callback)
        {
            LatestError = null;

            if (UpdateFeedReader == null)
            {
                throw new ArgumentException("An update feed reader is required; please set one before checking for updates");
            }

            if (source == null)
            {
                throw new ArgumentException("An update source was not specified");
            }

            lock (UpdatesToApply)
            {
                UpdatesToApply.Clear();
                var tasks = UpdateFeedReader.Read(source.GetUpdatesFeed());
                foreach (var t in tasks)
                {
                    if (ShouldStop)
                    {
                        return(false);
                    }
                    if (t.UpdateConditions.IsMet(t)) // Only execute if all conditions are met
                    {
                        UpdatesToApply.Add(t);
                    }
                }
            }

            if (ShouldStop)
            {
                return(false);
            }

            State = UpdateProcessState.Checked;
            if (callback != null)
            {
                callback.BeginInvoke(UpdatesToApply.Count, null, null);
            }

            if (UpdatesToApply.Count > 0)
            {
                return(true);
            }

            return(false);
        }
示例#3
0
        /// <summary>
        /// Check for updates synchronouly
        /// </summary>
        /// <param name="source">Updates source to use</param>
        public void CheckForUpdates(IUpdateSource source)
        {
            if (IsWorking)
            {
                throw new InvalidOperationException("Another update process is already in progress");
            }

            using (WorkScope.New(isWorking => IsWorking = isWorking))
            {
                if (UpdateFeedReader == null)
                {
                    throw new ArgumentException("An update feed reader is required; please set one before checking for updates");
                }

                if (source == null)
                {
                    throw new ArgumentException("An update source was not specified");
                }

                if (State != UpdateProcessState.NotChecked)
                {
                    throw new InvalidOperationException("Already checked for updates; to reset the current state call CleanUp()");
                }

                lock (UpdatesToApply)
                {
                    UpdatesToApply.Clear();
                    using (Stream s = source.GetUpdatesFeed())
                    {
                        var tasks = UpdateFeedReader.Read(s);
                        foreach (var t in tasks)
                        {
                            if (ShouldStop)
                            {
                                throw new UserAbortException();
                            }

                            if (t.UpdateConditions == null || t.UpdateConditions.IsMet(t)) // Only execute if all conditions are met
                            {
                                UpdatesToApply.Add(t);
                            }
                        }
                    }
                }

                State = UpdateProcessState.Checked;
            }
        }
示例#4
0
        private void TaskProgressCallback(UpdateProgressInfo currentStatus, IUpdateTask task)
        {
            if (ReportProgress == null)
            {
                return;
            }

            currentStatus.TaskDescription = task.Description;
            currentStatus.TaskId          = UpdatesToApply.IndexOf(task) + 1;

            //This was an assumed int, which meant we never reached 100% with an odd number of tasks
            float taskPerc = 100F / UpdatesToApply.Count;

            currentStatus.Percentage = (int)Math.Round((currentStatus.Percentage * taskPerc / 100) + (currentStatus.TaskId - 1) * taskPerc);

            ReportProgress(currentStatus);
        }
示例#5
0
        /// <summary>
        /// Check for updates synchronously
        /// </summary>
        public void CheckForUpdates()
        {
            if (IsWorking)
            {
                throw new InvalidOperationException("Another update process is already in progress");
            }
            else if (UpdateFeedReader == null)
            {
                throw new InvalidOperationException("UpdateFeedReader must be set before calling CheckForUpdates()");
            }
            else if (UpdateSource == null)
            {
                throw new InvalidOperationException("UpdateSource must be set before calling CheckForUpdates()");
            }

            using (WorkScope.New(isWorking => IsWorking = isWorking))
            {
                if (State != UpdateProcessState.NotChecked)
                {
                    throw new InvalidOperationException("Already checked for updates; to reset the current state call CleanUp()");
                }

                lock (UpdatesToApply)
                {
                    UpdatesToApply.Clear();
                    var tasks = UpdateFeedReader.Read(UpdateSource.GetUpdatesFeed());
                    foreach (var t in tasks)
                    {
                        if (ShouldStop)
                        {
                            throw new UserAbortException();
                        }

                        if (t.UpdateConditions == null || t.UpdateConditions.IsMet(t))                         // Only execute if all conditions are met
                        {
                            UpdatesToApply.Add(t);
                        }
                    }
                }

                State = UpdateProcessState.Checked;
            }
        }
示例#6
0
        /// <summary>
        /// Delete the temp folder as a whole and fail silently
        /// </summary>
        public void CleanUp()
        {
            Abort(true);

            lock (UpdatesToApply)
            {
                UpdatesToApply.Clear();
                State = UpdateProcessState.NotChecked;

                try
                {
                    Directory.Delete(TempFolder, true);
                }
                catch { }

                try
                {
                    Directory.Delete(BackupFolder, true);
                }
                catch { }
            }
        }
示例#7
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>
        /// <param name="updaterDoLogging">true if the updater writes to a log file; false otherwise</param>
        /// <param name="updaterShowConsole">true if the updater shows the console window; false otherwise</param>
        /// <returns>True if successful (unless a restart was required</returns>
        public void ApplyUpdates(bool relaunchApplication, bool updaterDoLogging, bool updaterShowConsole)
        {
            if (IsWorking)
            {
                throw new InvalidOperationException("Another update process is already in progress");
            }

            lock (UpdatesToApply)
            {
                using (WorkScope.New(isWorking => IsWorking = isWorking))
                {
                    bool revertToDefaultBackupPath = true;

                    // Set current directory the the application directory
                    // this prevents the updater from writing to e.g. c:\windows\system32
                    // if the process is started by autorun on windows logon.
                    // ReSharper disable AssignNullToNotNullAttribute
                    Environment.CurrentDirectory = Path.GetDirectoryName(ApplicationPath);
                    // ReSharper restore AssignNullToNotNullAttribute

                    // Make sure the current backup folder is accessible for writing from this process
                    string backupParentPath = Path.GetDirectoryName(Config.BackupFolder) ?? string.Empty;
                    if (Directory.Exists(backupParentPath) && 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(Config.BackupFolder))
                            {
                                FileSystem.DeleteDirectory(Config.BackupFolder);
                            }
                            revertToDefaultBackupPath = false;
                        }
                        catch (UnauthorizedAccessException)
                        {
                        }

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

                            if (!PermissionsCheck.HaveWritePermissionsForFolder(Config.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)
                    {
                        Config._backupFolder = Path.Combine(
                            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
                            Config.UpdateProcessName + "UpdateBackups" + DateTime.UtcNow.Ticks);

                        try
                        {
                            Directory.CreateDirectory(Config.BackupFolder);
                        }
                        catch (UnauthorizedAccessException ex)
                        {
                            // We can't backup, so we abort
                            throw new UpdateProcessFailedException("Could not create backup folder " + Config.BackupFolder, ex);
                        }
                    }

                    bool runPrivileged = false, hasColdUpdates = false;
                    State = UpdateProcessState.RollbackRequired;
                    foreach (var task in UpdatesToApply)
                    {
                        IUpdateTask t = task;
                        task.ProgressDelegate += status => TaskProgressCallback(status, t);

                        try
                        {
                            // Execute the task
                            task.ExecutionStatus = task.Execute(false);
                        }
                        catch (Exception ex)
                        {
                            task.ExecutionStatus = TaskExecutionStatus.Failed;                             // mark the failing task before rethrowing
                            throw new UpdateProcessFailedException("Update task execution failed: " + task.Description, ex);
                        }

                        if (task.ExecutionStatus == TaskExecutionStatus.RequiresAppRestart ||
                            task.ExecutionStatus == TaskExecutionStatus.RequiresPrivilegedAppRestart)
                        {
                            // Record that we have cold updates to run, and if required to run any of them privileged
                            runPrivileged  = runPrivileged || task.ExecutionStatus == TaskExecutionStatus.RequiresPrivilegedAppRestart;
                            hasColdUpdates = true;
                            continue;
                        }

                        // We are being quite explicit here - only Successful return values are considered
                        // to be Ok (cold updates are already handled above)
                        if (task.ExecutionStatus != TaskExecutionStatus.Successful)
                        {
                            throw new UpdateProcessFailedException("Update task execution failed: " + task.Description);
                        }
                    }

                    // If an application restart is required
                    if (hasColdUpdates)
                    {
                        var dto = new NauIpc.NauDto
                        {
                            Configs             = Instance.Config,
                            Tasks               = Instance.UpdatesToApply,
                            AppPath             = ApplicationPath,
                            WorkingDirectory    = Environment.CurrentDirectory,
                            RelaunchApplication = relaunchApplication,
                            LogItems            = Logger.LogItems,
                        };

                        NauIpc.ExtractUpdaterFromResource(Config.TempFolder, Instance.Config.UpdateExecutableName);

                        var info = new ProcessStartInfo
                        {
                            UseShellExecute  = true,
                            WorkingDirectory = Environment.CurrentDirectory,
                            FileName         = Path.Combine(Config.TempFolder, Instance.Config.UpdateExecutableName),
                            Arguments        =
                                string.Format(@"""{0}"" {1} {2}", Config.UpdateProcessName,
                                              updaterShowConsole ? "-showConsole" : string.Empty,
                                              updaterDoLogging ? "-log" : string.Empty),
                        };

                        if (!updaterShowConsole)
                        {
                            info.WindowStyle    = ProcessWindowStyle.Hidden;
                            info.CreateNoWindow = true;
                        }

                        // If we can't write to the destination folder, then lets try elevating priviledges.
                        if (runPrivileged || !PermissionsCheck.HaveWritePermissionsForFolder(Environment.CurrentDirectory))
                        {
                            info.Verb = "runas";
                        }

                        bool createdNew;
                        _shutdownMutex = new Mutex(true, Config.UpdateProcessName + "Mutex", out createdNew);

                        try
                        {
                            NauIpc.LaunchProcessAndSendDto(dto, info, Config.UpdateProcessName);
                        }
                        catch (Exception ex)
                        {
                            throw new UpdateProcessFailedException("Could not launch cold update process", ex);
                        }

                        Environment.Exit(0);
                    }

                    State = UpdateProcessState.AppliedSuccessfully;
                    UpdatesToApply.Clear();
                }
            }
        }
示例#8
0
        /// <summary>
        /// Check for updates synchronously
        /// </summary>
        public void CheckForUpdates()
        {
            if (IsWorking)
            {
                throw new InvalidOperationException("Another update process is already in progress");
            }
            else if (UpdateFeedReader == null)
            {
                throw new InvalidOperationException("UpdateFeedReader must be set before calling CheckForUpdates()");
            }
            else if (UpdateSource == null)
            {
                throw new InvalidOperationException("UpdateSource must be set before calling CheckForUpdates()");
            }

            using (WorkScope.New(isWorking => IsWorking = isWorking))
            {
                if (State != UpdateProcessState.NotChecked)
                {
                    throw new InvalidOperationException("Already checked for updates; to reset the current state call CleanUp()");
                }

                lock (UpdatesToApply)
                {
                    UpdatesToApply.Clear();
                    IList <IUpdateTask> tasks = null;
                    int currentRetry          = 0;
                    while (currentRetry < MaximumRetries)
                    {
                        ++currentRetry;
                        try
                        {
                            tasks = UpdateFeedReader.Read(UpdateSource.GetUpdatesFeed());
                            break;
                        }
                        catch (Exception ex)
                        {
                            Logger.Log(ex);

                            if (ex is WebException)
                            {
                                var e = ex as WebException;
                                if (e.Status == WebExceptionStatus.Timeout ||
                                    e.Status == WebExceptionStatus.ConnectFailure ||
                                    e.Status == WebExceptionStatus.NameResolutionFailure)
                                {
                                    throw new UpdateProcessFailedException("Failed to retrieve feed: " + ex.ToString());
                                }
                            }

                            if (currentRetry == MaximumRetries)
                            {
                                throw new UpdateProcessFailedException("Failed to retrieve feed: " + ex.ToString());
                            }

                            Thread.Sleep(RetriesTimeout);
                        }
                    }

                    foreach (var t in tasks)
                    {
                        if (ShouldStop)
                        {
                            throw new UserAbortException();
                        }

                        if (t.UpdateConditions == null || t.UpdateConditions.IsMet(t))                         // Only execute if all conditions are met
                        {
                            UpdatesToApply.Add(t);
                        }
                    }
                }

                State = UpdateProcessState.Checked;
            }
        }
示例#9
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);
        }