Provides a logical stream over a virtual hard disk (VHD).
This stream implementation provides a "view" over a VHD, such that the VHD appears to be an ordinary fixed VHD file, regardless of the true physical layout. This stream supports any combination of differencing, dynamic disks, and fixed disks.
Наследование: SparseStream
Пример #1
0
        private void CreateRemoteBlob()
        {
            var baseBlob = this.blobObjectFactory.Create(baseVhdBlobUri);

            if (!baseBlob.Exists())
            {
                throw new InvalidOperationException(String.Format("Base image to patch doesn't exist in blob storage: {0}", baseVhdBlobUri.Uri));
            }
            var blobVhdFooter = baseBlob.GetVhdFooter();

            long blobSize;
            VhdFilePath localBaseVhdPath;
            IEnumerable<Guid> childrenVhdIds;
            using (var vhdFile = new VhdFileFactory().Create(localVhd.FullName))
            {
                localBaseVhdPath = vhdFile.GetFilePathBy(blobVhdFooter.UniqueId);
                childrenVhdIds = vhdFile.GetChildrenIds(blobVhdFooter.UniqueId).ToArray();
                blobSize = vhdFile.Footer.VirtualSize;
            }

            FileMetaData fileMetaData = GetFileMetaData(baseBlob, localBaseVhdPath);

            var md5Hash = baseBlob.GetBlobMd5Hash();
            if (!md5Hash.SequenceEqual(fileMetaData.MD5Hash))
            {
                var message = String.Format("Patching cannot proceed, MD5 hash of base image in blob storage ({0}) and base VHD file ({1}) does not match ",
                                            baseBlob.Uri,
                                            localBaseVhdPath);
                throw new InvalidOperationException(message);
            }

            Program.SyncOutput.MessageCreatingNewPageBlob(blobSize);

            CopyBaseImageToDestination();

            using (var vds = new VirtualDiskStream(localVhd.FullName))
            {
                var streamExtents = vds.Extents.ToArray();
                var enumerable = streamExtents.Where(e => childrenVhdIds.Contains(e.Owner)).ToArray();
                foreach (var streamExtent in enumerable)
                {
                    var indexRange = streamExtent.Range;
                    destinationBlob.ClearPages(indexRange.StartIndex, indexRange.Length);
                }
            }

            using (var bmds = new BlobMetaDataScope(destinationBlob))
            {
                bmds.Current.RemoveBlobMd5Hash();
                bmds.Current.SetUploadMetaData(OperationMetaData);
                bmds.Complete();
            }
        }
        public static FileMetaData Create(string filePath)
        {
            var fileInfo = new FileInfo(filePath);
            if (!fileInfo.Exists)
            {
                throw new FileNotFoundException(filePath);
            }

            using (var stream = new VirtualDiskStream(filePath))
            {
                return new FileMetaData
                {
                    FileFullName = fileInfo.FullName,
                    CreatedDateUtc = DateTime.SpecifyKind(fileInfo.CreationTimeUtc, DateTimeKind.Utc),
                    LastModifiedDateUtc = DateTime.SpecifyKind(fileInfo.LastWriteTimeUtc, DateTimeKind.Utc),
                    Size = fileInfo.Length,
                    VhdSize = stream.Length,
                    MD5Hash = CalculateMd5Hash(stream, filePath)
                };
            }
        }
Пример #3
0
        public UploadParameters ValidateParameters()
        {
            BlobUri destinationUri;
            if (!BlobUri.TryParseUri(Destination, out destinationUri))
            {
                throw new ArgumentOutOfRangeException("Destination", this.Destination.ToString());
            }

            BlobUri baseImageUri = null;
            if (this.BaseImageUriToPatch != null)
            {
                if (!BlobUri.TryParseUri(BaseImageUriToPatch, out baseImageUri))
                {
                    throw new ArgumentOutOfRangeException("BaseImageUriToPatch", this.BaseImageUriToPatch.ToString());
                }

                if (!String.IsNullOrEmpty(destinationUri.Uri.Query))
                {
                    var message = String.Format(Rsrc.AddAzureVhdCommandSASUriNotSupportedInPatchMode, destinationUri.Uri);
                    throw new ArgumentOutOfRangeException("Destination", message);
                }
            }

            var storageCredentialsFactory = CreateStorageCredentialsFactory();

            PathIntrinsics currentPath = SessionState.Path;
            var filePath = new FileInfo(currentPath.GetUnresolvedProviderPathFromPSPath(LocalFilePath.ToString()));

            using (var vds = new VirtualDiskStream(filePath.FullName))
            {
                if (vds.DiskType == DiskType.Fixed)
                {
                    long divisor = Convert.ToInt64(Math.Pow(2, 9));
                    long rem = 0;
                    Math.DivRem(filePath.Length, divisor, out rem);
                    if (rem != 0)
                    {
                        throw new ArgumentOutOfRangeException("LocalFilePath", "Given vhd file is a corrupted fixed vhd");
                    }
                }
            }

            var parameters = new UploadParameters(
                destinationUri, baseImageUri, filePath, OverWrite.IsPresent,
                (NumberOfUploaderThreads) ?? DefaultNumberOfUploaderThreads)
            {
                Cmdlet = this,
                BlobObjectFactory = new CloudPageBlobObjectFactory(storageCredentialsFactory, TimeSpan.FromMinutes(1))
            };

            return parameters;
        }
Пример #4
0
 private static void AssertIfValidVhdSize(FileInfo fileInfo)
 {
     using (var stream = new VirtualDiskStream(fileInfo.FullName))
     {
         if (stream.Length > OneTeraByte)
         {
             var lengthString = stream.Length.ToString("N0", CultureInfo.CurrentCulture);
             var expectedLengthString = OneTeraByte.ToString("N0", CultureInfo.CurrentCulture);
             string message = String.Format("VHD size is too large ('{0}'), maximum allowed size is '{1}'.", lengthString, expectedLengthString);
             throw new InvalidOperationException(message);
         }
     }
 }
Пример #5
0
 protected static IEnumerable<DataWithRange> GetDataWithRangesToUpload(FileInfo vhdFile, UploadContext context)
 {
     var uploadableRanges = context.UploadableRanges;
     var manager = BufferManager.CreateBufferManager(Int32.MaxValue, MaxBufferSize);
     using (var vds = new VirtualDiskStream(vhdFile.FullName))
     {
         foreach (var range in uploadableRanges)
         {
             var localRange = range;
             yield return new DataWithRange(manager)
             {
                 Data = ReadBytes(vds, localRange, manager),
                 Range = localRange
             };
         }
     }
     yield break;
 }
Пример #6
0
        protected static void PopulateContextWithUploadableRanges(FileInfo vhdFile, UploadContext context, bool resume)
        {
            using (var vds = new VirtualDiskStream(vhdFile.FullName))
            {
                IEnumerable<IndexRange> ranges = vds.Extents.Select(e => e.Range).ToArray();

                var bs = new BufferedStream(vds);
                if (resume)
                {
                    var alreadyUploadedRanges = context.DestinationBlob.GetPageRanges().Select(pr => new IndexRange(pr.StartOffset, pr.EndOffset));
                    ranges = IndexRange.SubstractRanges(ranges, alreadyUploadedRanges);
                    context.AlreadyUploadedDataSize = alreadyUploadedRanges.Sum(ir => ir.Length);
                }
                var uploadableRanges = IndexRangeHelper.ChunkRangesBySize(ranges, PageSizeInBytes).ToArray();
                if (vds.DiskType == DiskType.Fixed)
                {
                    var nonEmptyUploadableRanges = GetNonEmptyRanges(bs, uploadableRanges).ToArray();
                    context.UploadableDataSize = nonEmptyUploadableRanges.Sum(r => r.Length);
                    context.UploadableRanges = nonEmptyUploadableRanges;
                }
                else
                {
                    context.UploadableDataSize = uploadableRanges.Sum(r => r.Length);
                    context.UploadableRanges = uploadableRanges;
                }
            }
        }