예제 #1
0
        /// <inheritdoc cref="IDeltaUpdate.ApplyDeltaFile"/>
        public async Task <bool> ApplyDeltaFile(
            TemporaryFolder tempFolder,
            string originalFileLocation,
            string newFileLocation,
            string deltaFileName,
            Stream deltaFileStream,
            Action <double>?progress = null)
        {
            if (OSHelper.ActiveOS != OSPlatform.Windows)
            {
                _logger.Error("We aren't on Windows so can't apply MSDiff update");
                return(false);
            }
            if (string.IsNullOrWhiteSpace(deltaFileName))
            {
                _logger.Error("Wasn't given a file location for the delta file");
                return(false);
            }

            //Put the delta file onto disk
            using var tmpDeltaFile = tempFolder.CreateTemporaryFile(deltaFileName);
            var tmpFileStream = tmpDeltaFile.GetStream();
            await deltaFileStream.CopyToAsync(tmpFileStream);

            tmpFileStream.Dispose();
            deltaFileStream.Dispose();

            //If baseFile + outputLocation are the same, copy it to a tmp file
            //and then give it that (deleting it after)
            TemporaryFile?tmpBaseFile = null;

            if (originalFileLocation == newFileLocation)
            {
                tmpBaseFile = tempFolder.CreateTemporaryFile();
                File.Copy(originalFileLocation, tmpBaseFile.Location);
                originalFileLocation = tmpBaseFile.Location;
            }

            //Make the updated file!
            File.Create(newFileLocation).Dispose();
            var wasApplySuccessful = ApplyDelta(ApplyFlags.None, originalFileLocation, tmpDeltaFile.Location, newFileLocation);

            tmpBaseFile?.Dispose();

            return(wasApplySuccessful);
        }
예제 #2
0
        /// <summary>
        /// Creates a delta file by going through the different ways of creating delta files and grabbing the one that made the smallest file
        /// </summary>
        /// <param name="tempFolder">Where the temp folder is located</param>
        /// <param name="baseFileLocation">Where the older version of the file exists</param>
        /// <param name="newFileLocation">Where the newer version of the file exists</param>
        /// <param name="deltaFileLocation">Where the delta file should be stored (If we are unable to store it in a stream)</param>
        /// <param name="intendedOs">What OS this delta file will be intended for</param>
        /// <param name="extension">Extension of the delta file</param>
        /// <param name="deltaFileStream">The contents of the delta file</param>
        /// <param name="progress">Progress of making the delta file (If we can report the progress back)</param>
        public static bool CreateDeltaFile(
            TemporaryFolder tempFolder,
            string baseFileLocation,
            string newFileLocation,
            string deltaFileLocation,
            OSPlatform?intendedOs,
            out string extension,
            out Stream?deltaFileStream,
            Action <double>?progress = null)
        {
            var os = intendedOs ?? OSHelper.ActiveOS;
            IReadOnlyList <IDeltaUpdate>?deltaUpdaters = null;

            lock (_updaterLock)
            {
                if (CachedUpdaters.ContainsKey(os))
                {
                    deltaUpdaters = CachedUpdaters[os];
                }
                else
                {
                    deltaUpdaters ??= DeltaUpdaters.GetUpdatersBasedOnOS(intendedOs ?? OSHelper.ActiveOS);
                    CachedUpdaters.Add(os, deltaUpdaters);
                }
            }
            var updaterCount = deltaUpdaters.Count;

            var progresses   = new double[updaterCount];
            var deltaResults = new List <DeltaCreationResult>(updaterCount);

            Parallel.For(0, updaterCount, i =>
            {
                var deltaUpdater = deltaUpdaters[i];
                var deltaFile    = tempFolder.CreateTemporaryFile();

                var successful = deltaUpdater.CreateDeltaFile(
                    tempFolder,
                    baseFileLocation,
                    newFileLocation,
                    deltaFile.Location,
                    out var stream,
                    pro =>
                {
                    progresses[i] = pro;
                    progress?.Invoke(progresses.Sum() / updaterCount);
                });

                if (successful)
                {
                    deltaResults.Add(
                        new DeltaCreationResult(deltaUpdater.Extension, deltaFile, stream));
                }
                else
                {
                    Logging.Warning("{0} was unable to make a delta file for {1}",
                                    nameof(deltaUpdater), baseFileLocation.GetRelativePath(newFileLocation));
                    deltaFile.Dispose();
                }

                if (progresses[i] < 1d)
                {
                    progresses[i] = 1d;
                    progress?.Invoke(progresses.Sum() / updaterCount);
                }
            });
예제 #3
0
        /// <summary>
        /// Creates a delta file and then adds it the <see cref="ZipArchive"/>
        /// </summary>
        /// <param name="tempFolder">Where the temp folder is located</param>
        /// <param name="zipArchive"><see cref="ZipArchive"/> to add the file too</param>
        /// <param name="baseFileLocation">Old file</param>
        /// <param name="newFileLocation">New file</param>
        /// <param name="intendedOs">What OS this delta file will be intended for</param>
        /// <param name="progress">Progress of creating delta file (If possible)</param>
        /// <param name="extensionEnd">What to add onto the end of the extension (If needed)</param>
        /// <returns>If we was able to create the delta file</returns>
        private bool AddDeltaFile(
            TemporaryFolder tempFolder,
            ZipArchive zipArchive,
            string baseFileLocation,
            string newFileLocation,
            OSPlatform?intendedOs    = null,
            Action <double>?progress = null,
            string?extensionEnd      = null)
        {
            //Create where the delta file can be stored to grab once made
            using var tmpDeltaFile = tempFolder.CreateTemporaryFile();

            //Try to create diff file, outputting extension (and maybe a stream) based on what was used to make it
            if (!DeltaCreation.CreateDeltaFile(
                    tempFolder,
                    baseFileLocation,
                    newFileLocation,
                    tmpDeltaFile.Location,
                    intendedOs,
                    out var extension,
                    out var deltaFileStream))
            {
                //Wasn't able to create delta file, report back as fail
                _logger.Error("Wasn't able to create delta file");
                return(false);
            }

            //Check that we got something to work with
            if (deltaFileStream == null && !File.Exists(tmpDeltaFile.Location))
            {
                _logger.Error("We have no delta file/stream to work off somehow");
                return(false);
            }

            //Get hash and filesize to add to file
            var newFileStream = File.OpenRead(newFileLocation);
            var newFilesize   = newFileStream.Length;

            /*Check that the delta file will take up less space, if not fail here
             * as it's not worth making it a delta file (Will take more time and processing power then just copying on the user's device)*/
            if ((deltaFileStream?.Length ?? new FileInfo(tmpDeltaFile.Location).Length) >= newFilesize)
            {
                _logger.Warning("{0} will take up more space as a delta file then as a \"new\" file, failing to trigger it being added as a new file", baseFileLocation.GetRelativePath(newFileLocation));
                newFileStream.Dispose();
                deltaFileStream?.Dispose();
                return(false);
            }

            var hash = SHA256Util.CreateSHA256Hash(newFileStream);

            newFileStream.Dispose();

            //Grab file and add it to the set of files
            deltaFileStream ??= tmpDeltaFile.GetStream(FileMode.Open);
            var addSuccessful = AddFile(
                zipArchive,
                deltaFileStream,
                baseFileLocation.GetRelativePath(newFileLocation) + extension + extensionEnd,
                filesize: newFilesize,
                sha256Hash: hash);

            //Dispose stream and report back if we was able to add file
            deltaFileStream.Dispose();
            return(addSuccessful);
        }
예제 #4
0
        private bool AddLoaderFile(
            TemporaryFolder temporaryFolder,
            ApplicationMetadata applicationMetadata,
            ZipArchive zipArchive,
            SemanticVersion newVersion,
            string applicationLocation,
            OSPlatform?intendedOs      = null,
            SemanticVersion?oldVersion = null,
            string?outputLocation      = null)
        {
            //TODO: See why this is making another .shasum file (but working)
            using var loaderLocation = temporaryFolder.CreateTemporaryFile(applicationMetadata.ApplicationName + ".exe");
            // ReSharper disable once LocalFunctionHidesMethod
            bool AddFile() => BinaryCreator.AddFile(
                zipArchive,
                loaderLocation.GetStream(FileMode.Open),
                applicationMetadata.ApplicationName + ".exe.load",
                false);

            //TODO: Grab metadata from .exe and drop it into Loader
            var iconLocation = Path.Combine(applicationLocation, "app.ico");

            iconLocation = File.Exists(iconLocation) ? iconLocation : null;

            var successful = LoaderCreator.CreateLoader(
                temporaryFolder,
                $"{newVersion.GetApplicationFolder()}\\{applicationMetadata.ApplicationName}.exe",
                iconLocation,
                loaderLocation.Location,
                applicationMetadata.ApplicationName,
                intendedOs);

            if (successful != LoadCreateStatus.Successful)
            {
                var canContinue = successful == LoadCreateStatus.UnableToCreate;
                _logger.Error("We wasn't able to create loader! (Going to fail file creation?: {0})", canContinue);
                return(canContinue);
            }
            if (oldVersion == null || !Directory.Exists(outputLocation))
            {
                return(AddFile());
            }

            //If we get here then we might also have the old loader, try to diff by using it
            foreach (var file in Directory.EnumerateFiles(outputLocation !, "*" + Extension))
            {
                if (string.IsNullOrWhiteSpace(file))
                {
                    _logger.Warning("We somehow got an entry for {0} which was nothing", outputLocation);
                    continue;
                }

                /*Don't try it with delta file, more then likely going to
                 * have diff loader itself and we can't work with that*/
                var fileName = Path.GetFileNameWithoutExtension(file);
                if (fileName.EndsWith("-delta") ||
                    fileName.ToVersion() != oldVersion)
                {
                    continue;
                }

                Stream?    stream = null;
                ZipArchive fileArch;
                try
                {
                    stream   = File.OpenRead(file);
                    fileArch = new ZipArchive(stream, ZipArchiveMode.Read);
                }
                catch (Exception e)
                {
                    stream?.Dispose();
                    _logger.Error(e);
                    continue;
                }

                //We want to grab the loader file
                var loaderFileIndex = fileArch.Entries.IndexOf(x => x?.Name == applicationMetadata.ApplicationName + ".exe.load");
                if (loaderFileIndex == -1)
                {
                    fileArch.Dispose();
                    continue;
                }

                var fileEntry = fileArch.Entries[loaderFileIndex];
                using var tmpFile = temporaryFolder.CreateTemporaryFile(Path.GetFileNameWithoutExtension(fileEntry.Name));
                fileEntry.ExtractToFile(tmpFile.Location, true);

                var deltaSuccessful =
                    AddDeltaFile(temporaryFolder,
                                 zipArchive,
                                 tmpFile.Location,
                                 loaderLocation.Location,
                                 extensionEnd: "load");
                if (!deltaSuccessful)
                {
                    _logger.Warning("Wasn't able to diff loader, just going to add the load in as normal");
                }
                fileArch.Dispose();
                return(deltaSuccessful || AddFile());
            }

            //If we get here then we can't do any kind of diff logic
            return(AddFile());
        }