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); }
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); } } }