Exemplo n.º 1
0
        /// <summary>
        /// Applies a <see cref="SingleFile"/> to a <see cref="TemporaryDirectory"/>.
        /// </summary>
        /// <param name="step">The <see cref="Archive"/> to apply.</param>
        /// <param name="localPath">The local path of the file.</param>
        /// <param name="workingDir">The <see cref="TemporaryDirectory"/> to apply the changes to.</param>
        /// <param name="handler">A callback object used when the the user needs to be informed about progress.</param>
        /// <exception cref="IOException">A path specified in <paramref name="step"/> is illegal.</exception>
        public static void Apply(this SingleFile step, string localPath, TemporaryDirectory workingDir, ITaskHandler handler)
        {
            #region Sanity checks
            if (step == null)
            {
                throw new ArgumentNullException(nameof(step));
            }
            if (string.IsNullOrEmpty(localPath))
            {
                throw new ArgumentNullException(nameof(localPath));
            }
            if (workingDir == null)
            {
                throw new ArgumentNullException(nameof(workingDir));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            // Use a copy of the original file because the source file is moved
            using var tempFile = new TemporaryFile("0install");
            // ReSharper disable once AccessToDisposedClosure
            handler.RunTask(new SimpleTask(Resources.CopyFiles, () => File.Copy(localPath, tempFile, overwrite: true)));
            step.Apply(tempFile, workingDir);
        }
Exemplo n.º 2
0
        /// <inheritdoc/>
        public string GetIcon(Uri iconUrl, ITaskHandler handler)
        {
            #region Sanity checks
            if (iconUrl == null)
            {
                throw new ArgumentNullException("iconUrl");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            string path = Path.Combine(DirectoryPath, new FeedUri(iconUrl).Escape());

            // Prevent file-exists race conditions
            lock (_lock)
            {
                // Download missing icons
                if (!File.Exists(path))
                {
                    using (var atomic = new AtomicWrite(path))
                    {
                        handler.RunTask(new DownloadFile(iconUrl, atomic.WritePath));
                        atomic.Commit();
                    }
                }
            }

            return(path);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Creates a archive containing the <see cref="InstallationDir"/>.
        /// </summary>
        /// <remarks>Sets <see cref="FeedBuilder.RetrievalMethod"/> and calls <see cref="FeedBuilder.CalculateDigest"/>.</remarks>
        /// <param name="archivePath">The path of the archive file to create.</param>
        /// <param name="archiveUrl">The URL where the archive will be uploaded.</param>
        /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
        /// <exception cref="InvalidOperationException"><see cref="Diff"/> was not called or <see cref="FeedBuilder.MainCandidate"/> is not set.</exception>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There was an error reading the installation files or writing the archive.</exception>
        /// <exception cref="UnauthorizedAccessException">Access to the file system was not permitted.</exception>
        public void CollectFiles([NotNull] string archivePath, [NotNull] Uri archiveUrl, [NotNull] ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(archivePath))
            {
                throw new ArgumentNullException(nameof(archivePath));
            }
            if (archiveUrl == null)
            {
                throw new ArgumentNullException(nameof(archiveUrl));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            if (InstallationDir == null)
            {
                throw new InvalidOperationException("Diff() must be called first.");
            }

            _feedBuilder.ImplementationDirectory = InstallationDir;
            _feedBuilder.CalculateDigest(handler);

            var mimeType = Archive.GuessMimeType(archivePath) ?? Archive.MimeTypeZip;
            using (var generator = ArchiveGenerator.Create(InstallationDir, archivePath, mimeType))
                handler.RunTask(generator);
            _feedBuilder.RetrievalMethod = new Archive {
                Href = archiveUrl, MimeType = mimeType, Size = new FileInfo(archivePath).Length
            };
        }
Exemplo n.º 4
0
        /// <summary>
        /// Downloads the installer from the web to a temporary file.
        /// </summary>
        /// <param name="url">The URL of the file to download.</param>
        /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
        /// <exception cref="IOException">A downloaded file could not be written to the disk.</exception>
        /// <exception cref="UnauthorizedAccessException">An operation failed due to insufficient rights.</exception>
        /// <remarks>Use either this or <see cref="SetLocal"/>.</remarks>
        public void Download([NotNull] Uri url, [NotNull] ITaskHandler handler)
        {
            _url = url;

            if (_tempDir != null)
            {
                _tempDir.Dispose();
            }
            _tempDir = new TemporaryDirectory("0publish");

            try
            {
                _localPath = Path.Combine(_tempDir, Path.GetFileName(url.LocalPath));
                handler.RunTask(new DownloadFile(url, _localPath));
            }
            #region Error handling
            catch (Exception)
            {
                _tempDir.Dispose();
                _tempDir   = null;
                _url       = null;
                _localPath = null;
                throw;
            }
            #endregion
        }
Exemplo n.º 5
0
        /// <summary>
        /// Calculates the <see cref="ManifestDigest"/>.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
        /// <exception cref="InvalidOperationException"><see cref="ImplementationDirectory"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There was a problem generating the manifest or detectng the executables.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to temporary files was not permitted.</exception>
        public void CalculateDigest(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            if (string.IsNullOrEmpty(ImplementationDirectory))
            {
                throw new InvalidOperationException("Implementation directory is not set.");
            }
            #endregion

            var newDigest = new ManifestDigest();

            // Generate manifest for each available format...
            foreach (var generator in ManifestFormat.Recommended.Select(format => new ManifestGenerator(ImplementationDirectory, format)))
            {
                // ... and add the resulting digest to the return value
                handler.RunTask(generator);
                newDigest.ParseID(generator.Result.CalculateDigest());
            }

            ManifestDigest = newDigest;
        }
Exemplo n.º 6
0
        private void DownloadMissingKey(FeedUri uri, FeedUri mirrorUrl, MissingKeySignature signature)
        {
            var keyUri = new Uri(mirrorUrl ?? uri, signature.KeyID + ".gpg");

            byte[] keyData;
            if (keyUri.IsFile)
            { // Load key file from local file
                keyData = File.ReadAllBytes(keyUri.LocalPath);
            }
            else
            { // Load key file from server
                try
                {
                    using (var keyFile = new TemporaryFile("0install-key"))
                    {
                        _handler.RunTask(new DownloadFile(keyUri, keyFile));
                        keyData = File.ReadAllBytes(keyFile);
                    }
                }
                #region Error handling
                catch (WebException ex)
                {
                    // Wrap exception to add context information
                    throw new SignatureException(string.Format(Resources.UnableToLoadKeyFile, uri), ex);
                }
                #endregion
            }

            Log.Info("Importing OpenPGP public key for " + signature.KeyID);
            _openPgp.ImportKey(keyData);
        }
Exemplo n.º 7
0
        /// <inheritdoc/>
        public string GetIcon(Uri iconUrl, ITaskHandler handler)
        {
            #region Sanity checks
            if (iconUrl == null) throw new ArgumentNullException(nameof(iconUrl));
            if (handler == null) throw new ArgumentNullException(nameof(handler));
            #endregion

            string path = Path.Combine(DirectoryPath, new FeedUri(iconUrl).Escape());

            // Prevent file-exists race conditions
            lock (_lock)
            {
                // Download missing icons
                if (!File.Exists(path))
                {
                    using (var atomic = new AtomicWrite(path))
                    {
                        handler.RunTask(new DownloadFile(iconUrl, atomic.WritePath));
                        atomic.Commit();
                    }
                }
            }

            return path;
        }
    /// <summary>
    /// Checks whether an implementation directory matches the expected digest.
    /// Throws <see cref="DigestMismatchException"/> if it does not match.
    /// </summary>
    /// <param name="path">The path of the directory ot check.</param>
    /// <param name="manifestDigest">The expected digest.</param>
    /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
    /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
    /// <exception cref="NotSupportedException"><paramref name="manifestDigest"/> does not list any supported digests.</exception>
    /// <exception cref="IOException">The directory could not be processed.</exception>
    /// <exception cref="UnauthorizedAccessException">Read access to the directory is not permitted.</exception>
    /// <exception cref="DigestMismatchException">The directory does not match the expected digest</exception>
    public static void Verify(string path, ManifestDigest manifestDigest, ITaskHandler handler)
    {
        #region Sanity checks
        if (string.IsNullOrEmpty(path))
        {
            throw new ArgumentNullException(nameof(path));
        }
        if (handler == null)
        {
            throw new ArgumentNullException(nameof(handler));
        }
        #endregion

        string expectedDigest = manifestDigest.Best ?? throw new NotSupportedException(Resources.NoKnownDigestMethod);
        var    format         = ManifestFormat.FromPrefix(expectedDigest);

        var builder = new ManifestBuilder(format);
        handler.RunTask(new ReadDirectory(path, builder));
        if (Verify(builder.Manifest, expectedDigest) == null)
        {
            string manifestFilePath = Path.Combine(path, Manifest.ManifestFile);
            var    expectedManifest = File.Exists(manifestFilePath) ? Manifest.Load(manifestFilePath, format) : null;
            throw new DigestMismatchException(
                      expectedDigest, actualDigest: builder.Manifest.CalculateDigest(),
                      expectedManifest, actualManifest: builder.Manifest);
        }
    }
Exemplo n.º 9
0
        private static Manifest GenerateManifest(string path, ManifestFormat format, ITaskHandler handler)
        {
            var generator = new ManifestGenerator(path, format);

            handler.RunTask(generator);
            return(generator.Result);
        }
Exemplo n.º 10
0
        /// <inheritdoc/>
        public virtual long Optimise(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            if (!Directory.Exists(DirectoryPath))
            {
                return(0);
            }
            if (Kind == StoreKind.ReadOnly && !WindowsUtils.IsAdministrator)
            {
                throw new NotAdminException(Resources.MustBeAdminToOptimise);
            }

            using (var run = new OptimiseRun(DirectoryPath))
            {
                handler.RunTask(ForEachTask.Create(
                                    name: string.Format(Resources.FindingDuplicateFiles, DirectoryPath),
                                    target: ListAll(),
                                    work: run.Work));
                return(run.SavedBytes);
            }
        }
Exemplo n.º 11
0
        public static TemporaryFile Download([NotNull] this DownloadRetrievalMethod retrievalMethod, [NotNull] ITaskHandler handler, [CanBeNull] ICommandExecutor executor = null)
        {
            #region Sanity checks
            if (retrievalMethod == null)
            {
                throw new ArgumentNullException("retrievalMethod");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            if (executor == null)
            {
                executor = new SimpleCommandExecutor();
            }
            if (retrievalMethod.Href == null)
            {
                throw new ArgumentException(Resources.HrefMissing, "retrievalMethod");
            }
            new PerTypeDispatcher <DownloadRetrievalMethod>(ignoreMissing: false)
            {
                // ReSharper disable AccessToDisposedClosure
                (Archive archive) =>
                {
                    // Guess MIME types now because the file ending is not known later
                    if (string.IsNullOrEmpty(archive.MimeType))
                    {
                        string mimeType = Archive.GuessMimeType(archive.Href.OriginalString);
                        executor.Execute(new SetValueCommand <string>(() => archive.MimeType, value => archive.MimeType = value, mimeType));
                    }
                },
                (SingleFile file) =>
                {
                    // Guess file name based on URL
                    if (string.IsNullOrEmpty(file.Destination))
                    {
                        string destination = file.Href.OriginalString.GetRightPartAtLastOccurrence('/').StripCharacters(Path.GetInvalidFileNameChars());
                        executor.Execute(new SetValueCommand <string>(() => file.Destination, value => file.Destination = value, destination));
                    }
                }
                // ReSharper restore AccessToDisposedClosure
            }.Dispatch(retrievalMethod);

            // Download the file
            var href           = ModelUtils.GetAbsoluteHref(retrievalMethod.Href, string.IsNullOrEmpty(executor.Path) ? null : new FeedUri(executor.Path));
            var downloadedFile = new TemporaryFile("0publish");
            handler.RunTask(new DownloadFile(href, downloadedFile)); // Defer task to handler

            // Set downloaded file size
            long newSize = new FileInfo(downloadedFile).Length;
            if (retrievalMethod.Size != newSize)
            {
                executor.Execute(new SetValueCommand <long>(() => retrievalMethod.Size, value => retrievalMethod.Size = value, newSize));
            }

            return(downloadedFile);
        }
Exemplo n.º 12
0
 private void Download(Uri href, string path)
 {
     using var atomic = new AtomicWrite(path);
     _handler.RunTask(new DownloadFile(href, atomic.WritePath)
     {
         BytesMaximum = MaximumIconSize
     });
     atomic.Commit();
 }
Exemplo n.º 13
0
        /// <inheritdoc/>
        public string AddArchives(IEnumerable <ArchiveFileInfo> archiveInfos, ManifestDigest manifestDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (archiveInfos == null)
            {
                throw new ArgumentNullException(nameof(archiveInfos));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            if (manifestDigest.Best == null)
            {
                throw new ArgumentException("No known digest method", nameof(manifestDigest));
            }
            #endregion

            if (Contains(manifestDigest))
            {
                throw new ImplementationAlreadyInStoreException(manifestDigest);
            }
            Log.Info("Caching implementation: " + manifestDigest.Best);

            // Extract to temporary directory inside the cache so it can be validated safely (no manipulation of directory while validating)
            string tempDir = GetTempDir();
            try
            {
                // Extract archives "over each other" in order
                foreach (var archiveInfo in archiveInfos)
                {
                    try
                    {
                        using (var extractor = ArchiveExtractor.Create(archiveInfo.Path, tempDir, archiveInfo.MimeType, archiveInfo.StartOffset))
                        {
                            extractor.SubDir      = archiveInfo.SubDir;
                            extractor.Destination = archiveInfo.Destination;
                            extractor.Tag         = manifestDigest;
                            handler.RunTask(extractor);
                        }
                    }
                    #region Error handling
                    catch (IOException ex)
                    {
                        string source = archiveInfo.OriginalSource?.ToStringRfc() ?? archiveInfo.Path;
                        throw new IOException(string.Format(Resources.FailedToExtractArchive, source), ex);
                    }
                    #endregion
                }

                return(VerifyAndAdd(Path.GetFileName(tempDir), manifestDigest, handler));
            }
            finally
            {
                DeleteTempDir(tempDir);
            }
        }
Exemplo n.º 14
0
        /// <summary>
        /// Runs the installer and waits for it to exit.
        /// </summary>
        /// <param name="handler">A callback object used when the the user is to be informed about progress.</param>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There is a problem access a temporary file.</exception>
        /// <exception cref="UnauthorizedAccessException">Read or write access to a temporary file is not permitted.</exception>
        public void RunInstaller(ITaskHandler handler)
        {
            if (string.IsNullOrEmpty(_localPath))
            {
                throw new InvalidOperationException();
            }

            var process = ProcessUtils.Start(_localPath);

            handler.RunTask(new SimpleTask(Resources.WaitingForInstaller, () => process.WaitForExit()));
        }
Exemplo n.º 15
0
        /// <inheritdoc/>
        public string AddDirectory(string path, ManifestDigest manifestDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            if (Contains(manifestDigest))
            {
                throw new ImplementationAlreadyInStoreException(manifestDigest);
            }
            Log.Info("Caching implementation: " + manifestDigest.AvailableDigests.First());

            // Copy to temporary directory inside the cache so it can be validated safely (no manipulation of directory while validating)
            string tempDir = GetTempDir();
            try
            {
                // Copy the source directory inside the cache so it can be validated safely (no manipulation of directory while validating)
                try
                {
                    handler.RunTask(new CopyDirectoryPosix(path, tempDir)
                    {
                        Tag = manifestDigest
                    });
                }
                #region Error handling
                catch (IOException ex)
                {
                    // Wrap too generic exceptions
                    // TODO: Make language independent
                    if (ex.Message.StartsWith("Access") && ex.Message.EndsWith("is denied."))
                    {
                        throw new UnauthorizedAccessException(ex.Message, ex);
                    }

                    // Pass other exceptions through
                    throw;
                }
                #endregion

                return(VerifyAndAdd(Path.GetFileName(tempDir), manifestDigest, handler));
            }
            finally
            {
                DeleteTempDir(tempDir);
            }
        }
Exemplo n.º 16
0
        /// <summary>
        /// Deletes this temporary directory from the <see cref="IStore"/> it is located in.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be asked questions or informed about IO tasks.</param>
        /// <exception cref="DirectoryNotFoundException">The directory could be found in the store.</exception>
        /// <exception cref="IOException">The directory could not be deleted.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the store is not permitted.</exception>
        public override void Delete(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null) throw new ArgumentNullException(nameof(handler));
            #endregion

            handler.RunTask(new SimpleTask(string.Format(Resources.DeletingDirectory, _path), () =>
            {
                DirectoryStore.DisableWriteProtection(_path);
                Directory.Delete(_path, recursive: true);
            }));
        }
Exemplo n.º 17
0
        /// <inheritdoc/>
        public Selections Solve(Requirements requirements)
        {
            #region Sanity checks
            if (requirements == null)
            {
                throw new ArgumentNullException("requirements");
            }
            if (requirements.InterfaceUri == null)
            {
                throw new ArgumentException(Resources.MissingInterfaceUri, "requirements");
            }
            #endregion

            Log.Info("Running Python Solver for: " + requirements);

            // Execute the external solver
            ISolverControl control;
            if (WindowsUtils.IsWindows)
            {
                control = new SolverControlBundled(_handler);                         // Use bundled Python on Windows
            }
            else
            {
                control = new SolverControlNative(_handler);  // Use native Python everywhere else
            }
            string arguments = GetSolverArguments(requirements);

            string result = null;
            _handler.RunTask(new SimpleTask(Resources.ExternalSolverRunning, () => { result = control.ExecuteSolver(arguments); }));

            // Flush in-memory cache in case external solver updated something on-disk
            _feedManager.Flush();

            // Detect when feeds get out-of-date
            _feedManager.Stale = result.Contains("<!-- STALE_FEEDS -->");

            // Parse StandardOutput data as XML
            _handler.CancellationToken.ThrowIfCancellationRequested();
            try
            {
                var selections = XmlStorage.FromXmlString <Selections>(result);
                selections.Normalize();
                return(selections);
            }
            #region Error handling
            catch (InvalidDataException ex)
            {
                Log.Warn("Solver result:" + Environment.NewLine + result);
                throw new SolverException(Resources.ExternalSolverOutputErrror, ex);
            }
            #endregion
        }
Exemplo n.º 18
0
        /// <inheritdoc/>
        public string AddDirectory(string path, ManifestDigest manifestDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException(nameof(path));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            if (manifestDigest.Best == null)
            {
                throw new ArgumentException("No known digest method", nameof(manifestDigest));
            }
            #endregion

            if (Contains(manifestDigest))
            {
                throw new ImplementationAlreadyInStoreException(manifestDigest);
            }
            Log.Info($"Caching implementation {manifestDigest} in {this}");

            // Copy to temporary directory inside the cache so it can be validated safely (no manipulation of directory while validating)
            string tempDir = GetTempDir();
            try
            {
                // Copy the source directory inside the cache so it can be validated safely (no manipulation of directory while validating)
                try
                {
                    handler.RunTask(new CloneDirectory(path, tempDir)
                    {
                        Tag = manifestDigest
                    });
                }
                #region Error handling
                catch (IOException ex)
                    // TODO: Make language independent
                    when(ex.Message.StartsWith("Access") && ex.Message.EndsWith("is denied."))
                    {
                        throw new UnauthorizedAccessException(ex.Message, ex);
                    }
                #endregion

                return(VerifyAndAdd(Path.GetFileName(tempDir), manifestDigest, handler));
            }
            finally
            {
                DeleteTempDir(tempDir);
            }
        }
Exemplo n.º 19
0
    /// <summary>
    /// Copies files or directories from another implementation fetched by an external 0install process.
    /// </summary>
    /// <param name="builder">The builder.</param>
    /// <param name="metadata">The path of the source and destination file or directory.</param>
    /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
    /// <exception cref="UnauthorizedAccessException">Access to a resource was denied.</exception>
    /// <exception cref="IOException">An IO operation failed.</exception>
    public static void CopyFrom(this IBuilder builder, CopyFromStep metadata, ITaskHandler handler)
    {
        if (metadata.Implementation == null)
        {
            throw new ArgumentException($"Must call {nameof(IRecipeStep.Normalize)}() first.", nameof(metadata));
        }

        handler.RunTask(new SimpleTask(string.Format(Resources.FetchingExternal, metadata.ID),
                                       () => ZeroInstallClient.Detect.FetchAsync(metadata.Implementation).Wait()));

        string path = ImplementationStores.Default().GetPath(metadata.Implementation);

        builder.CopyFrom(metadata, path, handler);
    }
Exemplo n.º 20
0
        /// <summary>
        /// Removes all applications from the <see cref="AppList"/> and undoes any desktop environment integration.
        /// </summary>
        /// <param name="handler">A callback object used when the the user is to be informed about the progress of long-running operations such as downloads.</param>
        /// <param name="machineWide">Apply the operation machine-wide instead of just for the current user.</param>
        public static void RemoveAllApps(ITaskHandler handler, bool machineWide)
        {
            #region Sanity checks
            if (handler == null) throw new ArgumentNullException(nameof(handler));
            #endregion

            using (var integrationManager = new IntegrationManager(handler, machineWide))
            {
                handler.RunTask(ForEachTask.Create(Resources.RemovingApplications, integrationManager.AppList.Entries.ToList(), integrationManager.RemoveApp));

                // Purge sync status, otherwise next sync would remove everything from server as well instead of restoring from there
                File.Delete(AppList.GetDefaultPath(machineWide) + SyncIntegrationManager.AppListLastSyncSuffix);
            }
        }
Exemplo n.º 21
0
 /// <summary>
 /// Deletes this implementation from the <see cref="IImplementationStore"/> it is located in.
 /// </summary>
 /// <param name="handler">A callback object used when the the user needs to be asked questions or informed about IO tasks.</param>
 /// <exception cref="KeyNotFoundException">No matching implementation could be found in the <see cref="IImplementationStore"/>.</exception>
 /// <exception cref="IOException">The implementation could not be deleted.</exception>
 /// <exception cref="UnauthorizedAccessException">Write access to the store is not permitted.</exception>
 public override void Delete(ITaskHandler handler)
 {
     try
     {
         handler.RunTask(new SimpleTask(
                             string.Format(Resources.DeletingImplementation, _digest),
                             () => ImplementationStore.Remove(_digest, handler)));
     }
     #region Error handling
     catch (ImplementationNotFoundException ex)
     {
         throw new KeyNotFoundException(ex.Message, ex);
     }
     #endregion
 }
Exemplo n.º 22
0
        private void Download(FeedUri feedUri)
        {
            SetLastCheckAttempt(feedUri);

            try
            {
                var download = new DownloadMemory(feedUri);
                _handler.RunTask(download);
                ImportFeed(download.GetData(), feedUri);
            }
            catch (WebException ex) when(!feedUri.IsLoopback)
            {
                if (_handler.Verbosity == Verbosity.Batch)
                {
                    Log.Info(string.Format(Resources.FeedDownloadError, feedUri) + " " + Resources.TryingFeedMirror);
                }
                else
                {
                    Log.Warn(string.Format(Resources.FeedDownloadError, feedUri) + " " + Resources.TryingFeedMirror);
                }
                try
                {
                    var download = new DownloadMemory(GetMirrorUrl(feedUri))
                    {
                        NoCache = Refresh
                    };
                    _handler.RunTask(download);
                    ImportFeed(download.GetData(), feedUri);
                }
                catch (WebException)
                {
                    // Report the original problem instead of mirror errors
                    throw ex.PreserveStack();
                }
            }
        }
Exemplo n.º 23
0
        /// <summary>
        /// Deletes this temporary directory from the <see cref="IStore"/> it is located in.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be asked questions or informed about IO tasks.</param>
        /// <exception cref="DirectoryNotFoundException">The directory could be found in the store.</exception>
        /// <exception cref="IOException">The directory could not be deleted.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the store is not permitted.</exception>
        public override void Delete(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            handler.RunTask(new SimpleTask(string.Format(Resources.DeletingDirectory, _path), () =>
            {
                DirectoryStore.DisableWriteProtection(_path);
                Directory.Delete(_path, recursive: true);
            }));
        }
Exemplo n.º 24
0
        /// <summary>
        /// Downloads and imports a remote key file.
        /// </summary>
        /// <exception cref="WebException">The key file could not be downloaded from the internet.</exception>
        /// <exception cref="SignatureException">The downloaded key file is damaged.</exception>
        /// <exception cref="IOException">A problem occurs while writing trust configuration.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to the trust configuration is not permitted.</exception>
        private void DownloadKey([NotNull] Uri keyUri)
        {
            var download = new DownloadMemory(keyUri);

            _handler.RunTask(download);
            try
            {
                _openPgp.ImportKey(download.GetData());
            }
            #region Error handling
            catch (InvalidDataException ex)
            {
                // Wrap exception since only certain exception types are allowed
                throw new SignatureException(ex.Message, ex);
            }
            #endregion
        }
Exemplo n.º 25
0
        /// <inheritdoc/>
        protected override string VerifyAndAdd(string tempID, ManifestDigest expectedDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            var callingIdentity = WindowsIdentity.GetCurrent();
            Debug.Assert(callingIdentity != null);

            using (_serviceIdentity.Impersonate()) // Use system rights instead of calling user
            {
                try
                {
                    var tempDirectory = new DirectoryInfo(Path.Combine(DirectoryPath, tempID));
                    try
                    {
                        handler.RunTask(new SimpleTask(Resources.SettingFilePermissions, tempDirectory.ResetAcl)
                        {
                            Tag = expectedDigest
                        });
                    }
                    catch (IndexOutOfRangeException)
                    {
                        // Workaround for .NET 2.0 bug
                    }

                    string result = base.VerifyAndAdd(tempID, expectedDigest, handler);
                    _eventLog.WriteEntry(string.Format(Resources.SuccessfullyAddedImplementation, callingIdentity.Name, expectedDigest.AvailableDigests.FirstOrDefault(), DirectoryPath));
                    return(result);
                }
                #region Error handling
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception)
                {
                    _eventLog.WriteEntry(string.Format(Resources.FailedToAddImplementation, callingIdentity.Name, expectedDigest.AvailableDigests.FirstOrDefault(), DirectoryPath), EventLogEntryType.Warning);
                    throw;
                }
                #endregion
            }
        }
Exemplo n.º 26
0
        /// <inheritdoc/>
        public Selections Solve(Requirements requirements)
        {
            #region Sanity checks
            if (requirements == null)
            {
                throw new ArgumentNullException(nameof(requirements));
            }
            if (requirements.InterfaceUri == null)
            {
                throw new ArgumentException(Resources.MissingInterfaceUri, nameof(requirements));
            }
            #endregion

            Selections selections = null;
            _handler.RunTask(new SimpleTask(Resources.ExternalSolverRunning, () =>
            {
                using (var control = new JsonControl(GetStartInfo())
                {
                    { "confirm", args => DoConfirm((string)args[0]) },
                    { "confirm-keys", args => DoConfirmKeys(new FeedUri((string)args[0]), args[1].ReparseAsJson <Dictionary <string, string[][]> >()) },
                    { "update-key-info", args => null }
                })
                {
                    control.Invoke(args =>
                    {
                        if ((string)args[0] == "ok")
                        {
                            _feedManager.Stale = args[1].ReparseAsJson(new { stale = false }).stale;
                            selections         = XmlStorage.FromXmlString <Selections>((string)args[2]);
                        }
                        else
                        {
                            throw new SolverException(((string)args[1]).Replace("\n", Environment.NewLine));
                        }
                    }, "select", GetEffectiveRequirements(requirements), _feedManager.Refresh);
                    while (selections == null)
                    {
                        control.HandleStderr();
                        control.HandleNextChunk();
                    }
                    control.HandleStderr();
                }
            }));

            return(selections);
        }
Exemplo n.º 27
0
        /// <summary>
        /// Removes all applications from the <see cref="AppList"/> and undoes any desktop environment integration.
        /// </summary>
        /// <param name="handler">A callback object used when the the user is to be informed about the progress of long-running operations such as downloads.</param>
        /// <param name="machineWide">Apply the operation machine-wide instead of just for the current user.</param>
        public static void RemoveAllApps(ITaskHandler handler, bool machineWide)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            using (var integrationManager = new IntegrationManager(handler, machineWide))
            {
                handler.RunTask(ForEachTask.Create(Resources.RemovingApplications, integrationManager.AppList.Entries.ToList(), integrationManager.RemoveApp));

                // Purge sync status, otherwise next sync would remove everything from server as well instead of restoring from there
                File.Delete(AppList.GetDefaultPath(machineWide) + SyncIntegrationManager.AppListLastSyncSuffix);
            }
        }
Exemplo n.º 28
0
        /// <summary>
        /// Applies a <see cref="Archive"/> to a <see cref="TemporaryDirectory"/>.
        /// </summary>
        /// <param name="step">The <see cref="Archive"/> to apply.</param>
        /// <param name="localPath">The local path of the archive.</param>
        /// <param name="workingDir">The <see cref="TemporaryDirectory"/> to apply the changes to.</param>
        /// <param name="handler">A callback object used when the the user needs to be informed about progress.</param>
        /// <param name="tag">The <see cref="ITaskHandler"/> tag used by <paramref name="handler"/>; can be <c>null</c>.</param>
        /// <exception cref="IOException">A path specified in <paramref name="step"/> is illegal.</exception>
        public static void Apply([NotNull] this Archive step, [NotNull] string localPath, [NotNull] TemporaryDirectory workingDir, [NotNull] ITaskHandler handler, [CanBeNull] object tag = null)
        {
            #region Sanity checks
            if (step == null)
            {
                throw new ArgumentNullException(nameof(step));
            }
            if (string.IsNullOrEmpty(localPath))
            {
                throw new ArgumentNullException(nameof(localPath));
            }
            if (workingDir == null)
            {
                throw new ArgumentNullException(nameof(workingDir));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            #region Path validation
            if (!string.IsNullOrEmpty(step.Destination))
            {
                string destination = FileUtils.UnifySlashes(step.Destination);
                if (FileUtils.IsBreakoutPath(destination))
                {
                    throw new IOException(string.Format(Resources.RecipeInvalidPath, destination));
                }
            }
            #endregion

            if (string.IsNullOrEmpty(step.MimeType))
            {
                throw new IOException(Resources.UnknownArchiveType);
            }

            using (var extractor = ArchiveExtractor.Create(localPath, workingDir, step.MimeType))
            {
                extractor.SubDir      = step.Extract;
                extractor.Destination = FileUtils.UnifySlashes(step.Destination);
                extractor.Tag         = tag;
                handler.RunTask(extractor);
            }
        }
Exemplo n.º 29
0
        /// <inheritdoc/>
        protected override string VerifyAndAdd(string tempID, ManifestDigest expectedDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            var callingIdentity = WindowsIdentity.GetCurrent();
            Debug.Assert(callingIdentity != null);

            using (_serviceIdentity.Impersonate()) // Use system rights instead of calling user
            {
                try
                {
                    var tempDirectory = new DirectoryInfo(System.IO.Path.Combine(Path, tempID));
                    try
                    {
                        handler.RunTask(new SimpleTask($"{Resources.SettingFilePermissions} ({expectedDigest.Best})", tempDirectory.ResetAcl)
                        {
                            Tag = expectedDigest.Best
                        });
                    }
                    catch (IndexOutOfRangeException)
                    {
                        // Workaround for .NET 2.0 bug
                    }

                    string result = base.VerifyAndAdd(tempID, expectedDigest, handler);
                    Log.Info(string.Format(Resources.SuccessfullyAddedImplementation, callingIdentity.Name, expectedDigest.AvailableDigests.FirstOrDefault(), Path));
                    return(result);
                }
                catch (OperationCanceledException)
                {
                    throw;
                }
                catch (Exception ex)
                {
                    Log.Warn(string.Format(Resources.FailedToAddImplementation, callingIdentity.Name, expectedDigest.AvailableDigests.FirstOrDefault(), Path) + Environment.NewLine + ex.Message);
                    throw;
                }
            }
        }
Exemplo n.º 30
0
    /// <summary>
    /// Downloads an <see cref="Implementation"/> to the <see cref="IImplementationStore"/>.
    /// </summary>
    /// <param name="implementation">The implementation to download.</param>
    /// <param name="tag">A <see cref="ITask.Tag"/> used to group progress bars.</param>
    protected virtual void Fetch(Implementation implementation, string tag)
    {
        // Use mutex to detect in-progress download of same implementation in other processes
        string mutexName = $"0install-fetcher-{implementation.ManifestDigest.Best}";

        using var mutex = new Mutex(false, mutexName);
        try
        {
            while (!mutex.WaitOne(100, exitContext: false)) // NOTE: Might be blocked more than once
            {
                Handler.RunTask(new WaitTask(Resources.WaitingForDownload, mutex)
                {
                    Tag = tag
                });
            }
        }
        #region Error handling
        catch (AbandonedMutexException)
        {
            Log.Warn($"Mutex '{mutexName}' was abandoned by another instance");
            // Abandoned mutexes get acquired despite exception
        }
        #endregion

        try
        {
            // Check if another process added the implementation in the meantime
            if (GetPath(implementation) != null)
            {
                return;
            }

            if (implementation.RetrievalMethods.Count == 0)
            {
                throw new NotSupportedException(string.Format(Resources.NoRetrievalMethod, implementation.ID));
            }
            Retrieve(implementation, tag);
        }
        finally
        {
            mutex.ReleaseMutex();
        }
    }
Exemplo n.º 31
0
        public static Manifest VerifyDirectory(string directory, ManifestDigest expectedDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException(nameof(directory));
            }
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            string?expectedDigestValue = expectedDigest.Best;
            if (string.IsNullOrEmpty(expectedDigestValue))
            {
                throw new NotSupportedException(Resources.NoKnownDigestMethod);
            }
            var format = ManifestFormat.FromPrefix(expectedDigestValue);

            var generator = new ManifestGenerator(directory, format)
            {
                Tag = expectedDigest
            };
            handler.RunTask(generator);
            var    manifest = generator.Manifest;
            string digest   = manifest.CalculateDigest();

            if (digest != expectedDigestValue)
            {
                var offsetManifest = TryFindOffset(manifest, expectedDigestValue);
                if (offsetManifest != null)
                {
                    return(offsetManifest);
                }

                string manifestFilePath = Path.Combine(directory, Manifest.ManifestFile);
                var    expectedManifest = File.Exists(manifestFilePath) ? Manifest.Load(manifestFilePath, format) : null;
                throw new DigestMismatchException(expectedDigestValue, digest, expectedManifest, manifest);
            }

            return(manifest);
        }
Exemplo n.º 32
0
        /// <inheritdoc/>
        public virtual bool Remove(ManifestDigest manifestDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            #endregion

            string path = GetPath(manifestDigest);
            if (path == null)
            {
                return(false);
            }
            if (Kind == ImplementationStoreKind.ReadOnly && !WindowsUtils.IsAdministrator)
            {
                throw new NotAdminException(Resources.MustBeAdminToRemove);
            }
            if (path == Locations.InstallBase && WindowsUtils.IsWindows)
            {
                Log.Warn(Resources.NoStoreSelfRemove);
                return(false);
            }
            if (WindowsUtils.IsWindowsVista)
            {
                if (!UseRestartManager(path, handler))
                {
                    return(false);
                }
            }

            handler.RunTask(new SimpleTask(string.Format(Resources.DeletingImplementation, manifestDigest), () =>
            {
                DisableWriteProtection(path);

                string tempDir = Path.Combine(DirectoryPath, Path.GetRandomFileName());
                Log.Info("Attempting atomic delete: " + path);
                Directory.Move(path, tempDir);
                Directory.Delete(tempDir, recursive: true);
            }));

            return(true);
        }
Exemplo n.º 33
0
        public static Manifest VerifyDirectory(string directory, ManifestDigest expectedDigest, ITaskHandler handler)
        {
            #region Sanity checks
            if (string.IsNullOrEmpty(directory))
            {
                throw new ArgumentNullException("directory");
            }
            if (handler == null)
            {
                throw new ArgumentNullException("handler");
            }
            #endregion

            string expectedDigestValue = expectedDigest.Best;
            if (string.IsNullOrEmpty(expectedDigestValue))
            {
                throw new NotSupportedException(Resources.NoKnownDigestMethod);
            }
            var format = ManifestFormat.FromPrefix(expectedDigestValue);

            var generator = new ManifestGenerator(directory, format)
            {
                Tag = expectedDigest
            };
            handler.RunTask(generator);
            var    actualManifest    = generator.Result;
            string actualDigestValue = actualManifest.CalculateDigest();

            string manifestFilePath = Path.Combine(directory, Manifest.ManifestFile);
            var    expectedManifest = File.Exists(manifestFilePath) ? Manifest.Load(manifestFilePath, format) : null;

            if (actualDigestValue != expectedDigestValue)
            {
                throw new DigestMismatchException(
                          expectedDigestValue,
                          actualDigestValue,
                          // Only log the complete manifests in verbose mode
                          (handler.Verbosity > 0) ? expectedManifest : null,
                          (handler.Verbosity > 0) ? actualManifest : null);
            }

            return(actualManifest);
        }
Exemplo n.º 34
0
        /// <summary>
        /// Calculates the <see cref="ManifestDigest"/>.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
        /// <exception cref="InvalidOperationException"><see cref="ImplementationDirectory"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There was a problem generating the manifest or detectng the executables.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to temporary files was not permitted.</exception>
        public void CalculateDigest(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null) throw new ArgumentNullException("handler");
            if (string.IsNullOrEmpty(ImplementationDirectory)) throw new InvalidOperationException("Implementation directory is not set.");
            #endregion

            var newDigest = new ManifestDigest();

            // Generate manifest for each available format...
            foreach (var generator in ManifestFormat.Recommended.Select(format => new ManifestGenerator(ImplementationDirectory, format)))
            {
                // ... and add the resulting digest to the return value
                handler.RunTask(generator);
                newDigest.ParseID(generator.Result.CalculateDigest());
            }

            ManifestDigest = newDigest;
        }
Exemplo n.º 35
0
        /// <summary>
        /// Detects <see cref="Candidates"/> in the <see cref="ImplementationDirectory"/>.
        /// </summary>
        /// <param name="handler">A callback object used when the the user needs to be informed about IO tasks.</param>
        /// <exception cref="InvalidOperationException"><see cref="ImplementationDirectory"/> is <see langword="null"/> or empty.</exception>
        /// <exception cref="OperationCanceledException">The user canceled the task.</exception>
        /// <exception cref="IOException">There was a problem generating the manifest or detectng the executables.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to temporary files was not permitted.</exception>
        public void DetectCandidates(ITaskHandler handler)
        {
            #region Sanity checks
            if (handler == null) throw new ArgumentNullException("handler");
            if (string.IsNullOrEmpty(ImplementationDirectory)) throw new InvalidOperationException("Implementation directory is not set.");
            #endregion

            _candidates.Clear();

            handler.RunTask(new SimpleTask(Resources.DetectingCandidates,
                () => _candidates.AddRange(Detection.ListCandidates(new DirectoryInfo(ImplementationDirectory)))));

            MainCandidate = _candidates.FirstOrDefault();
        }
Exemplo n.º 36
0
 private static Manifest GenerateManifest(string path, ManifestFormat format, ITaskHandler handler)
 {
     var generator = new ManifestGenerator(path, format);
     handler.RunTask(generator);
     return generator.Result;
 }