예제 #1
0
    private Manifest GenerateManifest(string path, string?subdir)
    {
        var builder = new ManifestBuilder(_algorithm);

        if (Directory.Exists(path))
        {
            if (!string.IsNullOrEmpty(subdir))
            {
                throw new OptionException(Resources.TooManyArguments + Environment.NewLine + subdir.EscapeArgument(), null);
            }

            Handler.RunTask(new ReadDirectory(path, builder));
            return(builder.Manifest);
        }
        else if (File.Exists(path))
        {
            var extractor = ArchiveExtractor.For(Archive.GuessMimeType(path), Handler);
            Handler.RunTask(new ReadFile(path, stream => extractor.Extract(builder, stream, subdir)));
            return(builder.Manifest);
        }
        else
        {
            throw new FileNotFoundException(string.Format(Resources.FileOrDirNotFound, path));
        }
    }
예제 #2
0
        private Manifest GenerateManifest(string path, string?subdir)
        {
            if (Directory.Exists(path))
            {
                if (!string.IsNullOrEmpty(subdir))
                {
                    throw new OptionException(Resources.TooManyArguments + Environment.NewLine + subdir.EscapeArgument(), null);
                }

                var generator = new ManifestGenerator(path, _algorithm);
                Handler.RunTask(generator);
                return(generator.Manifest);
            }
            else if (File.Exists(path))
            {
                using var tempDir = new TemporaryDirectory("0install");

                using (var extractor = ArchiveExtractor.Create(path, tempDir, Archive.GuessMimeType(path)))
                {
                    extractor.Extract = subdir;
                    Handler.RunTask(extractor);
                }

                var generator = new ManifestGenerator(tempDir, _algorithm);
                Handler.RunTask(generator);
                return(generator.Manifest);
            }
            else
            {
                throw new FileNotFoundException(string.Format(Resources.FileOrDirNotFound, path));
            }
        }
        /// <summary>
        /// Downloads a specific file.
        /// </summary>
        public async Task DownloadAndExtract(DownloadProgressChangedEventHandler progressChanged)
        {
            // Start the modification download.
            byte[] data;
            using (WebClient client = new WebClient())
            {
                client.DownloadProgressChanged += progressChanged;
                data = await client.DownloadDataTaskAsync(Uri);
            }

            /* Extract to Temp Directory */
            string temporaryDirectory = GetTemporaryDirectory();
            var    archiveExtractor   = new ArchiveExtractor();
            await archiveExtractor.ExtractPackageAsync(data, temporaryDirectory);

            /* Get name of package. */
            var configReader = new ConfigReader <ModConfig>();
            var configs      = configReader.ReadConfigurations(temporaryDirectory, ModConfig.ConfigFileName);
            var loaderConfig = LoaderConfigReader.ReadConfiguration();

            foreach (var config in configs)
            {
                string configId        = config.Object.ModId;
                string configDirectory = Path.GetDirectoryName(config.Path);
                string targetDirectory = Path.Combine(loaderConfig.ModConfigDirectory, configId);
                IOEx.MoveDirectory(configDirectory, targetDirectory);
            }

            Directory.Delete(temporaryDirectory, true);
        }
예제 #4
0
        private static async Task Main(string[] args)
        {
            var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).AppSettings.Settings;

            await Parser.Default.ParseArguments <GenerateArchiveOptions, ExtractArchiveOptions, ModifyDllOptions>(args)
            .MapResult(
                (GenerateArchiveOptions opts) => GenerateArchive(opts),
                (ExtractArchiveOptions opts) => ExtractArchive(opts),
                (ModifyDllOptions opts) => ModifyDll(opts), errors => Task.FromResult(0));

            async Task ModifyDll(ModifyDllOptions opts)
            {
                var csDir = opts.CsgoDirectory ?? config["csgoDirectory"].Value;

                WriteResult(await DllModifier.ModifyDll(csDir));
            }

            async Task GenerateArchive(GenerateArchiveOptions opts)
            {
                var inputDir  = opts.DirectoryPath ?? config["archiveDirectory"].Value;
                var outputDir = opts.OutputPath ?? config["outputDirectory"].Value;

                WriteResult(await ArchiveGenerator.GenerateArchive(opts.DirectoryPath, opts.OutputPath));
            }

            async Task ExtractArchive(ExtractArchiveOptions opts)
            {
                var csDir     = opts.DirectoryPath ?? config["csgoDirectory"].Value;
                var outputDir = opts.OutputPath ?? config["archiveDirectory"].Value;

                WriteResult(await ArchiveExtractor.ExtractArchive(csDir, outputDir));
            }
        }
예제 #5
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);
            }
        }
예제 #6
0
        public void ShouldExtractPackageToTemporaryFolder()
        {
            var compressionUtilityMock = new Mock <ICompressionUtility>();

            var uuid              = "d1c9102e-7106-4355-a4a4-0c9b7f9b3541";
            var inputFilename     = "c:\\users\\johnsmith\\my documents\\" + uuid + ".tar";
            var archiveExtraction = new ArchiveExtractor(compressionUtilityMock.Object).Extract(inputFilename);

            archiveExtraction.WorkingDirectory.Should().Be(ArchiveExtractor.TemporaryFolder + Path.DirectorySeparatorChar + uuid);
            archiveExtraction.Uuid.Should().Be(uuid);
        }
예제 #7
0
    public void Hardlink()
    {
        using var tempDir = new TemporaryDirectory("0install-test-archive");
        var builder = new DirectoryBuilder(tempDir);
        using var stream = typeof(ArchiveExtractorTestBase).GetEmbeddedStream(FileName);
        ArchiveExtractor.For(MimeType, new SilentTaskHandler())
                        .Extract(builder, stream);

        FileUtils.AreHardlinked(Path.Combine(tempDir, "hardlink"), Path.Combine(tempDir, "subdir1", "regular"))
                 .Should().BeTrue(because: "'regular' and 'hardlink' should be hardlinked together");
    }
예제 #8
0
        private void ExtractOriginalData(string gameDirectory, string workingDirectory, string file)
        {
            string sourceFile      = Path.Combine(gameDirectory, file);
            string targetDirectory = Path.Combine(workingDirectory, Path.GetFileName(file) + ".extracted");
            string infoDirectory   = Path.Combine(workingDirectory, Path.GetFileName(file) + ".info");

            using (IFileDataWrapper data = StreamFileDataWrapper.FromFile(sourceFile))
            {
                ArchiveExtractor archiveExtractor = new ArchiveExtractor(targetDirectory, infoDirectory, data);
                archiveExtractor.Unpack();
            }
        }
예제 #9
0
        private void BuildImplementation(IBuilder builder)
        {
            for (int i = 0; i < (AdditionalArgs.Count + 1) / 3; i++)
            {
                string path     = AdditionalArgs[i * 3 + 1];
                string mimeType = (AdditionalArgs.Count > i * 3 + 3)
                    ? AdditionalArgs[i * 3 + 3]
                    : Archive.GuessMimeType(AdditionalArgs[i * 3 + 1]);
                string?subDir = (AdditionalArgs.Count > i * 3 + 2) ? AdditionalArgs[i * 3 + 2] : null;

                var extractor = ArchiveExtractor.For(mimeType, Handler);
                Handler.RunTask(new ReadFile(path, stream => extractor.Extract(builder, stream, subDir)));
            }
        }
예제 #10
0
        /// <summary>
        /// Downloads a specific file.
        /// </summary>
        public async Task DownloadAndExtract(DownloadProgressChangedEventHandler progressChanged)
        {
            // Start the modification download.
            byte[] data;
            using (WebClient client = new WebClient())
            {
                client.DownloadProgressChanged += progressChanged;
                data = await client.DownloadDataTaskAsync(Uri);
            }

            /* Extract to Temp Directory */
            string temporaryDirectory = GetTemporaryDirectory();
            var    archiveExtractor   = new ArchiveExtractor();
            await archiveExtractor.ExtractPackageAsync(data, temporaryDirectory);

            /* Get name of package. */
            var configs = ConfigReader <ModConfig> .ReadConfigurations(temporaryDirectory, ModConfig.ConfigFileName, default, int.MaxValue);
예제 #11
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);
            }
        }
예제 #12
0
        private void BuildImplementation(IBuilder builder)
        {
            for (int i = 0; i < (AdditionalArgs.Count + 1) / 3; i++)
            {
                string path     = AdditionalArgs[i * 3 + 1];
                string mimeType = (AdditionalArgs.Count > i * 3 + 3)
                    ? AdditionalArgs[i * 3 + 3]
                    : Archive.GuessMimeType(AdditionalArgs[i * 3 + 1]);
                string?subDir = (AdditionalArgs.Count > i * 3 + 2) ? AdditionalArgs[i * 3 + 2] : null;

                void Callback(Stream stream)
                => ArchiveExtractor.For(mimeType, Handler)
                .Extract(builder, stream, subDir);

                Handler.RunTask(
                    Uri.TryCreate(path, UriKind.Absolute, out var uri) && !uri.IsFile
                        ? new DownloadFile(uri, Callback)
                        : new ReadFile(path, Callback));
            }
        }
예제 #13
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">A tag used to associate composite task with a specific operation; can be null.</param>
        /// <exception cref="IOException">A path specified in <paramref name="step"/> is illegal.</exception>
        /// <exception cref="ArgumentException"><see cref="Archive.Normalize"/> was not called for <paramref name="step"/>.</exception>
        public static void Apply(this Archive step, string localPath, TemporaryDirectory workingDir, ITaskHandler handler, 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

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

            using var extractor = ArchiveExtractor.Create(
                      localPath,
                      workingDir,
                      step.MimeType ?? throw new ArgumentException($"{nameof(step.Normalize)} was not called.", nameof(step)),
                      step.StartOffset);
            extractor.Extract      = step.Extract;
            extractor.TargetSuffix = FileUtils.UnifySlashes(step.Destination);
            extractor.Tag          = tag;
            handler.RunTask(extractor);
        }
예제 #14
0
        protected async Task <bool> DownloadAndExtractAsync(string url,
                                                            string destination,
                                                            ArchiveExtractor extractor,
                                                            CancellationToken cancellationToken)
        {
            Log.Verbose($"Downloading from '{url}'");

            HttpResponseMessage result;

            try
            {
                result = await Http.DefaultHttpClient.GetAsync(url, cancellationToken);
            }
            catch (HttpRequestException ex)
            {
                Log.Error($"Downloading asset failed: {ex.Message}");
                return(false);
            }

            if (!result.IsSuccessStatusCode)
            {
                Log.Error($"Failed to download '{url}'");
                throw new InvalidOperationException("Installation failed");
            }

            var filename = Path.GetFileName(url);
            var ext      = filename.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase)
                ? ".tar.gz"
                : Path.GetExtension(filename);

            using (var tmp = new TempFile(ext))
                using (var stream = new FileStream(tmp.Path, FileMode.Create))
                {
                    await result.Content.CopyToAsync(stream);

                    Log.Verbose($"Extracting '{filename}' to '{destination}'");

                    return(extractor(tmp.Path, destination));
                }
        }
예제 #15
0
        void DownloadEmulator()
        {
            if (!Directory.Exists(ServiceTools.Storage.Source.PathEmulator))
            {
                Directory.CreateDirectory(ServiceTools.Storage.Source.PathEmulator);

                WebDownloadClient download = new WebDownloadClient(0, "https://www.zerpico.ru/retrolauncher/mednafen.zip");

                download.FileName = Path.Combine(ServiceTools.Storage.Source.PathEmulator, download.Url.ToString().Substring(download.Url.ToString().LastIndexOf("/") + 1));

                download.DownloadCompleted += ((e, a) =>
                {
                    ArchiveExtractor.ExtractAll(download.FileName, ServiceTools.Storage.Source.PathEmulator, true);

                    System.Windows.Application.Current.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Background,
                                                                         (Action) delegate()
                    {
                        DownloadManager.Instance.ClearDownload(0);
                    });
                });

                string filePath = download.FileName;
                string tempPath = filePath + ".tmp";

                download.CheckUrl();
                if (download.HasError)
                {
                    return;
                }

                download.TempDownloadPath = tempPath;
                download.AddedOn          = DateTime.UtcNow;
                download.CompletedOn      = DateTime.MinValue;


                // Add the download to the downloads list
                DownloadManager.Instance.DownloadsList.Add(download);
                download.Start();
            }
        }
예제 #16
0
        /// <summary>
        /// Executes a <see cref="Recipe"/>.
        /// </summary>
        /// <param name="recipe">The recipe to execute.</param>
        /// <param name="manifestDigest">The digest the result of the recipe should produce.</param>
        /// <exception cref="OperationCanceledException">A download or IO task was canceled from another thread.</exception>
        /// <exception cref="WebException">A file could not be downloaded from the internet.</exception>
        /// <exception cref="NotSupportedException">A file format, protocal, etc. is unknown or not supported.</exception>
        /// <exception cref="IOException">A downloaded file could not be written to the disk or extracted.</exception>
        /// <exception cref="ImplementationAlreadyInStoreException">There is already an <see cref="Implementation"/> with the specified <paramref name="manifestDigest"/> in the store.</exception>
        /// <exception cref="UnauthorizedAccessException">Write access to <see cref="IStore"/> is not permitted.</exception>
        /// <exception cref="DigestMismatchException">An <see cref="Implementation"/>'s <see cref="Archive"/>s don't match the associated <see cref="ManifestDigest"/>.</exception>
        private void Cook([NotNull] Recipe recipe, ManifestDigest manifestDigest)
        {
            Handler.CancellationToken.ThrowIfCancellationRequested();

            // Fail fast on unsupported archive type
            foreach (var archive in recipe.Steps.OfType <Archive>())
            {
                ArchiveExtractor.VerifySupport(archive.MimeType);
            }

            var downloadedFiles = new List <TemporaryFile>();

            try
            {
                foreach (var downloadStep in recipe.Steps.OfType <DownloadRetrievalMethod>())
                {
                    downloadedFiles.Add(Download(downloadStep, tag: manifestDigest));
                }

                // More efficient special-case handling for Archive-only cases
                if (recipe.Steps.All(step => step is Archive))
                {
                    ApplyArchives(recipe.Steps.Cast <Archive>().ToList(), downloadedFiles, manifestDigest);
                }
                else
                {
                    ApplyRecipe(recipe, downloadedFiles, manifestDigest);
                }
            }
            finally
            {
                foreach (var downloadedFile in downloadedFiles)
                {
                    downloadedFile.Dispose();
                }
            }
        }
예제 #17
0
 public void TestForZip()
 {
     ArchiveExtractor.For(Archive.MimeTypeZip, new SilentTaskHandler())
     .Should().BeOfType <ZipExtractor>();
 }