private async Task <Tuple <Guid, string> > GetExpandedPackageData(string volumePath, CancellationToken cancellationToken) { Logger.Debug("Getting GUID and extracted path from volume {0}...", volumePath); var wrapper = new DiskPartWrapper(); var mountedVhd = false; try { var allDrives = DriveInfo.GetDrives().Where(d => d.IsReady && d.DriveFormat == "NTFS").Select(d => d.Name.ToLowerInvariant()).ToArray(); var existing = await MountVolumeHelper.GetVolumeIdentifiers().ConfigureAwait(false); Logger.Debug("Mounting {0}...", volumePath); await wrapper.MountVhd(volumePath, cancellationToken).ConfigureAwait(false); mountedVhd = true; var newVolumes = (await MountVolumeHelper.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."); } var dir = new DirectoryInfo(newDrives[0]); var msixFolderName = dir.EnumerateDirectories().FirstOrDefault()?.EnumerateDirectories().FirstOrDefault()?.Name; if (msixFolderName == null) { throw new InvalidOperationException("Could not read the content of the mounted file."); } return(new Tuple <Guid, string>(newVolumes[0], msixFolderName)); } finally { if (mountedVhd) { Logger.Debug("Dismounting {0}...", volumePath); await wrapper.DismountVhd(volumePath, 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); } } }
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); } } } }