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