public async Task CreateVolume(
            string packagePath,
            string volumePath,
            long?customSizeInBytes,
            CancellationToken cancellationToken       = default,
            IProgress <ProgressData> progressReporter = null)
        {
            if (volumePath == null)
            {
                throw new ArgumentNullException(nameof(volumePath), "Volume path must be empty.");
            }

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

            Logger.Debug("Unpacking {0} with MSIXMGR...", packagePath);
            progressReporter?.Report(new ProgressData(20, $"Unpacking {Path.GetFileName(packagePath)}..."));

            MsixMgrWrapper.FileType fileType;

            switch (Path.GetExtension(volumePath).ToLowerInvariant())
            {
            case FileConstants.AppAttachVhdxExtension:
                fileType = MsixMgrWrapper.FileType.Vhdx;
                break;

            case FileConstants.AppAttachVhdExtension:
                fileType = MsixMgrWrapper.FileType.Vhd;
                break;

            case FileConstants.AppAttachCimExtension:
                fileType = MsixMgrWrapper.FileType.Cim;
                break;

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

            long size;

            if (customSizeInBytes.HasValue && customSizeInBytes.Value > 0)
            {
                size = customSizeInBytes.Value;
            }
            else
            {
                ISizeCalculator sizeCalculator;

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

                case FileConstants.AppAttachCimExtension:
                    sizeCalculator = new CimSizeCalculator();
                    break;

                default:
                    throw new NotSupportedException("Extension " + Path.GetExtension(volumePath) + " is not supported.");
                }

                size = await sizeCalculator.GetRequiredSize(packagePath, cancellationToken : cancellationToken).ConfigureAwait(false);
            }

            if (fileType == MsixMgrWrapper.FileType.Cim)
            {
                size = (long)Math.Max(5, size / (1024.0 * 1024));
            }

            Logger.Info("Expanding MSIX...");
            await this.MsixMgr.UnpackEx(
                packagePath,
                volumePath,
                fileType,
                (uint)size,
                true,
                true,
                Path.GetFileNameWithoutExtension(packagePath),
                cancellationToken).ConfigureAwait(false);
        }
Exemplo n.º 2
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);
                }
            }
        }