Exemplo n.º 1
0
        public async Task CreateVolume(
            string packagePath,
            string volumePath,
            long?customSize,
            CancellationToken cancellationToken       = default,
            IProgress <ProgressData> progressReporter = null)
        {
            if (packagePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath), "Package path must not be empty.");
            }

            if (volumePath == null)
            {
                throw new ArgumentNullException(nameof(volumePath), "Volume path must not be empty.");
            }

            var packageFileInfo = new FileInfo(packagePath);

            if (!packageFileInfo.Exists)
            {
                throw new FileNotFoundException($"File {packagePath} does not exist.", packagePath);
            }

            switch (Path.GetExtension(volumePath).ToLowerInvariant())
            {
            case FileConstants.AppAttachVhdExtension:
            case FileConstants.AppAttachVhdxExtension:
                break;

            default:
                throw new NotSupportedException($"Disk format {Path.GetExtension(volumePath)} is not supported.");
            }

            var volumeFileInfo = new FileInfo(volumePath);

            if (volumeFileInfo.Directory != null && !volumeFileInfo.Directory.Exists)
            {
                volumeFileInfo.Directory.Create();
            }

            var tmpPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + Path.GetExtension(volumePath));

            using var progress = new WrappedProgress(progressReporter);

            // ReSharper disable once UnusedVariable
            var progressSize           = customSize <= 0 ? progress.GetChildProgress(30) : null;
            var progressInitializeDisk = progress.GetChildProgress(100);
            var progressExpand         = progress.GetChildProgress(120);

            try
            {
                long minimumSize;
                if (customSize.HasValue && customSize.Value > 0)
                {
                    minimumSize = 1024 * 1024 * customSize.Value;
                }
                else
                {
                    ISizeCalculator sizeCalculator = new VhdSizeCalculator();
                    minimumSize = await sizeCalculator.GetRequiredSize(packagePath, cancellationToken : cancellationToken).ConfigureAwait(false);
                }

                var wrapper = new DiskPartWrapper();

                try
                {
                    Logger.Debug("Getting drives (NTFS, ready) and volumes...");
                    var allDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).ToArray();
                    foreach (var item in allDrives)
                    {
                        Logger.Debug("* Drive: " + item);
                    }

                    var allVolumes = await MountVolumeHelper.GetVolumeIdentifiers().ConfigureAwait(false);

                    foreach (var item in allDrives)
                    {
                        Logger.Debug("* Volume: " + item);
                    }

                    await wrapper.CreateVhdAndAssignDriveLetter(tmpPath, minimumSize, cancellationToken, progressInitializeDisk).ConfigureAwait(false);

                    var newVolumes = (await MountVolumeHelper.GetVolumeIdentifiers().ConfigureAwait(false)).Except(allVolumes).ToArray();
                    foreach (var item in newVolumes)
                    {
                        Logger.Debug("* New volume: " + item);
                    }

                    var newDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).Except(allDrives).ToArray();
                    foreach (var item in newDrives)
                    {
                        Logger.Debug("* New drive: " + item);
                    }

                    if (newDrives.Length != 1 || newVolumes.Length != 1)
                    {
                        throw new InvalidOperationException("Could not mount the drive.");
                    }

                    cancellationToken.ThrowIfCancellationRequested();
                    await this.ExpandMsix(packagePath, newDrives.First() + Path.GetFileNameWithoutExtension(packagePath), cancellationToken, progressExpand).ConfigureAwait(false);
                }
                finally
                {
                    await wrapper.DismountVhd(tmpPath, cancellationToken).ConfigureAwait(false);
                }

                if (File.Exists(tmpPath))
                {
                    File.Move(tmpPath, volumeFileInfo.FullName, true);
                }
            }
            finally
            {
                if (File.Exists(tmpPath))
                {
                    File.Delete(tmpPath);
                }
            }
        }
Exemplo n.º 2
0
        public async Task CreateVolume(string packagePath, string volumePath, uint vhdSize, bool extractCertificate, bool generateScripts, CancellationToken cancellationToken = default, IProgress <ProgressData> progressReporter = null)
        {
            if (packagePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath));
            }

            if (volumePath == null)
            {
                throw new ArgumentNullException(nameof(packagePath));
            }

            var packageFileInfo = new FileInfo(packagePath);

            if (!packageFileInfo.Exists)
            {
                throw new FileNotFoundException($"File {packagePath} does not exist.", packagePath);
            }

            var volumeFileInfo = new FileInfo(volumePath);

            if (volumeFileInfo.Directory != null && !volumeFileInfo.Directory.Exists)
            {
                volumeFileInfo.Directory.Create();
            }

            var tmpPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N") + ".vhd");

            using (var progress = new WrappedProgress(progressReporter))
            {
                // ReSharper disable once UnusedVariable
                var progressSize           = vhdSize <= 0 ? progress.GetChildProgress(30) : null;
                var progressStopService    = progress.GetChildProgress(10);
                var progressInitializeDisk = progress.GetChildProgress(100);
                // var progressNewPartition = progress.GetChildProgress(30);
                // var progressFormatVolume = progress.GetChildProgress(80);
                var progressStartService = progress.GetChildProgress(10);
                var progressExpand       = progress.GetChildProgress(120);
                var progressScripts      = generateScripts ? progress.GetChildProgress(10) : null;

                try
                {
                    var minimumSize = vhdSize > 0 ? 1024 * 1024 * vhdSize : await GetVhdSize(packagePath, cancellationToken : cancellationToken).ConfigureAwait(false);

                    bool requiresRestart;
                    try
                    {
                        requiresRestart = await StopService(cancellationToken, progressStopService).ConfigureAwait(false);
                    }
                    catch (Exception)
                    {
                        requiresRestart = false;
                    }

                    Guid   volumeGuid;
                    var    wrapper = new DiskPartWrapper();
                    string pkgFullName;

                    try
                    {
                        var allDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).ToArray();

                        var existing = await this.GetVolumeIdentifiers().ConfigureAwait(false);

                        await wrapper.CreateVhdAndAssignDriveLetter(tmpPath, minimumSize, cancellationToken, progressInitializeDisk).ConfigureAwait(false);

                        var newVolumes = (await this.GetVolumeIdentifiers().ConfigureAwait(false)).Except(existing).ToArray();

                        var newDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).Except(allDrives).ToArray();

                        if (newDrives.Length != 1 || newVolumes.Length != 1)
                        {
                            throw new InvalidOperationException("Could not mount the drive.");
                        }

                        volumeGuid = newVolumes[0];
                        cancellationToken.ThrowIfCancellationRequested();
                        pkgFullName = await this.ExpandMsix(packagePath, newDrives.First() + Path.GetFileNameWithoutExtension(packagePath), cancellationToken, progressExpand).ConfigureAwait(false);
                    }
                    finally
                    {
                        await wrapper.DismountVhd(tmpPath, cancellationToken).ConfigureAwait(false);

                        if (requiresRestart)
                        {
                            try
                            {
                                await StartService(cancellationToken, progressStartService).ConfigureAwait(false);
                            }
                            catch (Exception e)
                            {
                                Logger.Warn(e, "Could not restart the service ShellHWDetection.");
                            }
                        }
                    }

                    if (File.Exists(tmpPath))
                    {
                        if (generateScripts)
                        {
                            await CreateScripts(volumeFileInfo.FullName, Path.GetFileNameWithoutExtension(packagePath), volumeGuid, pkgFullName, cancellationToken, progressScripts).ConfigureAwait(false);
                        }

                        await CreateJson(volumeFileInfo.FullName, Path.GetFileNameWithoutExtension(packagePath), volumeGuid, pkgFullName, cancellationToken, progressScripts).ConfigureAwait(false);

                        if (extractCertificate)
                        {
                            ISigningManager certMgr = this.signingManager;
                            if (certMgr == null)
                            {
                                certMgr = await this.managerFactory.GetProxyFor(SelfElevationLevel.AsInvoker, cancellationToken).ConfigureAwait(false);
                            }

                            cancellationToken.ThrowIfCancellationRequested();

                            // ReSharper disable once AssignNullToNotNullAttribute
                            await certMgr.ExtractCertificateFromMsix(packagePath, Path.Combine(volumeFileInfo.DirectoryName, Path.GetFileNameWithoutExtension(volumeFileInfo.FullName)) + ".cer", cancellationToken).ConfigureAwait(false);
                        }

                        File.Move(tmpPath, volumeFileInfo.FullName, true);
                    }
                }
                finally
                {
                    if (File.Exists(tmpPath))
                    {
                        File.Delete(tmpPath);
                    }
                }
            }
        }