/// <summary> /// Reads the volume descriptors for /// </summary> /// <param name="extentVds">The anchor volume extent information.</param> /// <returns>Returns true if the volume descriptors were read from the image successfully.</returns> private bool ReadVolumeDescriptors(UdfFileExtent extentVds) { byte[] buffer = new byte[SectorSize]; long location = extentVds.Position; while (location < extentVds.Length && location < this.imageSize) { this.stream.Seek(location << SectorSizeLog, (int)SeekOrigin.Begin, IntPtr.Zero); if (!this.stream.ReadSafe(buffer, buffer.Length)) { return(false); } VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, buffer.Length); switch ((VolumeDescriptorType)tag.Identifier) { case VolumeDescriptorType.Terminating: // Found terminating descriptor. Image is valid. return(true); case VolumeDescriptorType.Partition: if (this.Partitions.Count >= MaxPartitions) { return(false); } this.ReadPartitionDescriptor(buffer); break; case VolumeDescriptorType.LogicalVolume: if (this.LogicalVolumes.Count >= MaxLogicalVolumes || !this.ReadLogicalDescriptor(buffer)) { return(false); } break; } location++; } // Did not find the terminating descriptor. Not a valid image. return(false); }
/// <summary> /// Reads the file and directory structure from the image. /// </summary> /// <returns>Returns true if the file system is valid.</returns> private bool ReadFileStructure() { foreach (var volume in this.LogicalVolumes) { // Ensure the volume and parittion are valid. if (!this.ValidateVolumePartition(volume)) { return(false); } int volIndex = this.LogicalVolumes.IndexOf(volume); LongAllocationDescriptor nextExtent = volume.FileSetLocation; if (nextExtent.Length < VirtualSectorSize) { return(false); } byte[] buffer = new byte[nextExtent.Length]; this.ReadData(volIndex, nextExtent, buffer); VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, buffer.Length); if (tag.Identifier != (int)VolumeDescriptorType.FileSet) { return(false); } UdfFileSet fs = new UdfFileSet(); fs.RecordingTime.Parse(16, buffer); fs.RootDirICB.Parse(400, buffer); volume.FileSet = fs; if (!this.ReadRecord(this.RootDirectory as UdfRecord, volIndex, fs.RootDirICB, MaxRecurseLevels)) { return(false); } } return(true); }
/// <summary> /// Reads the Anchor Volume pointer from the image. /// </summary> /// <returns>Returns true if the pointer was found.</returns> private UdfFileExtent ReadAnchorVolumePointer() { UdfFileExtent result = null; byte[] buffer = new byte[SectorSize]; this.stream.Seek(-buffer.Length, (int)SeekOrigin.End, IntPtr.Zero); if (!this.stream.ReadSafe(buffer, buffer.Length)) { return(result); } VolumeTag tag = new VolumeTag(); if (tag.Parse(0, buffer, buffer.Length) && tag.Identifier == (short)VolumeDescriptorType.AnchorVolumePtr) { result = new UdfFileExtent(); result.Parse(16, buffer); } return(result); }
/// <summary> /// Reads the data from the image for a record. /// </summary> /// <param name="item">The item to read the data into.</param> /// <param name="volumeIndex">The index of the volume the file resides on.</param> /// <param name="lad">The long allocation descriptor of the file.</param> /// <param name="numRecurseAllowed">The number of recursions allowed before the method fails.</param> /// <returns>Returns true if the record was read successfully.</returns> private bool ReadRecordData(UdfRecord item, int volumeIndex, LongAllocationDescriptor lad, int numRecurseAllowed) { if (this.itemCount > MaxItems) { return(false); } LogicalVolume volume = this.LogicalVolumes[volumeIndex]; if (lad.Length != volume.BlockSize) { return(false); } // Read the record. int size = lad.Length; byte[] buffer = new byte[size]; if (!this.ReadData(volumeIndex, lad, buffer)) { return(false); } // Validate the tag is a file. VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, size); if (tag.Identifier != (short)VolumeDescriptorType.File) { return(false); } // Validate the IcbTage indicates file or directory. item.IcbTag.Parse(16, buffer); if (item.IcbTag.FileType != IcbFileType.Directory && item.IcbTag.FileType != IcbFileType.File) { return(false); } item.Parse(buffer); int extendedAttrLen = UdfHelper.Get32(168, buffer); int allocDescriptorsLen = UdfHelper.Get32(172, buffer); if ((extendedAttrLen & 3) != 0) { return(false); } int position = 176; if (extendedAttrLen > size - position) { return(false); } position += extendedAttrLen; IcbDescriptorType desctType = item.IcbTag.DescriptorType; if (allocDescriptorsLen > size - position) { return(false); } if (desctType == IcbDescriptorType.Inline) { // If the file data is inline, read it in now since we have it. item.IsInline = true; item.InlineData = UdfHelper.Readbytes(position, buffer, allocDescriptorsLen); } else { // Otherwise read the information about where the file is located for later. item.IsInline = false; item.InlineData = new byte[0]; if ((desctType != IcbDescriptorType.Short) && (desctType != IcbDescriptorType.Long)) { return(false); } for (int index = 0; index < allocDescriptorsLen;) { FileExtent extent = new FileExtent(); if (desctType == IcbDescriptorType.Short) { if (index + 8 > allocDescriptorsLen) { return(false); } ShortAllocationDescriptor sad = new ShortAllocationDescriptor(); sad.Parse(position + index, buffer); extent.Position = sad.Position; extent.Length = sad.Length; extent.PartitionReference = lad.Location.PartitionReference; index += 8; } else { if (index + 16 > allocDescriptorsLen) { return(false); } LongAllocationDescriptor ladNew = new LongAllocationDescriptor(); ladNew.Parse(position + index, buffer); extent.Position = ladNew.Location.Position; extent.PartitionReference = ladNew.Location.PartitionReference; extent.Length = ladNew.Length; index += 16; } item.Extents.Add(extent); } } if (item.IcbTag.IsDirectory) { if (!item.CheckChunkSizes() || !this.CheckItemExtents(volumeIndex, item)) { return(false); } buffer = new byte[0]; if (!this.ReadFromFile(volumeIndex, ref item, ref buffer)) { return(false); } item._size = 0; item.Extents.Clear(); size = buffer.Length; int processedTotal = 0; int processedCur = -1; while (processedTotal < size || processedCur == 0) { UdfFileInformation fileId = new UdfFileInformation(); fileId.Parse(processedTotal, buffer, (size - processedTotal), ref processedCur); if (!fileId.IsItLinkParent) { // Recursively read the contentst of the drirectory UdfRecord fileItem = new UdfRecord(); fileItem.Id = fileId.Identifier; if (fileItem.Id.Data != null) { this.fileNameLengthTotal += fileItem.Id.Data.Length; } if (this.fileNameLengthTotal > MaxFileNameLength) { return(false); } fileItem._Parent = item; item.Subitems.Add(fileItem); if (item.Subitems.Count > MaxFiles) { return(false); } this.ReadRecord(fileItem, volumeIndex, fileId.Icb, numRecurseAllowed); } processedTotal += processedCur; } } else { if (item.Extents.Count > MaxExtents - this.numExtents) { return(false); } this.numExtents += item.Extents.Count; if (item.InlineData.Length > MaxInlineExtentsSize - this.inlineExtentsSize) { return(false); } this.inlineExtentsSize += item.InlineData.Length; } this.itemCount++; return(true); }
/// <summary> /// Reads the volume descriptors for /// </summary> /// <param name="extentVds">The anchor volume extent information.</param> /// <returns>Returns true if the volume descriptors were read from the image successfully.</returns> private bool ReadVolumeDescriptors(UdfFileExtent extentVds) { byte[] buffer = new byte[SectorSize]; long location = extentVds.Position; while (location < extentVds.Length && location < this.imageSize) { this.stream.Seek(location << SectorSizeLog, (int)SeekOrigin.Begin, IntPtr.Zero); if (!this.stream.ReadSafe(buffer, buffer.Length)) { return false; } VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, buffer.Length); switch ((VolumeDescriptorType)tag.Identifier) { case VolumeDescriptorType.Terminating: // Found terminating descriptor. Image is valid. return true; case VolumeDescriptorType.Partition: if (this.Partitions.Count >= MaxPartitions) { return false; } this.ReadPartitionDescriptor(buffer); break; case VolumeDescriptorType.LogicalVolume: if (this.LogicalVolumes.Count >= MaxLogicalVolumes || !this.ReadLogicalDescriptor(buffer)) { return false; } break; } location++; } // Did not find the terminating descriptor. Not a valid image. return false; }
/// <summary> /// Reads the data from the image for a record. /// </summary> /// <param name="item">The item to read the data into.</param> /// <param name="volumeIndex">The index of the volume the file resides on.</param> /// <param name="lad">The long allocation descriptor of the file.</param> /// <param name="numRecurseAllowed">The number of recursions allowed before the method fails.</param> /// <returns>Returns true if the record was read successfully.</returns> private bool ReadRecordData(UdfRecord item, int volumeIndex, LongAllocationDescriptor lad, int numRecurseAllowed) { if (this.itemCount > MaxItems) { return false; } LogicalVolume volume = this.LogicalVolumes[volumeIndex]; if (lad.Length != volume.BlockSize) { return false; } // Read the record. int size = lad.Length; byte[] buffer = new byte[size]; if (!this.ReadData(volumeIndex, lad, buffer)) { return false; } // Validate the tag is a file. VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, size); if (tag.Identifier != (short)VolumeDescriptorType.File) { return false; } // Validate the IcbTage indicates file or directory. item.IcbTag.Parse(16, buffer); if (item.IcbTag.FileType != IcbFileType.Directory && item.IcbTag.FileType != IcbFileType.File) { return false; } item.Parse(buffer); int extendedAttrLen = UdfHelper.Get32(168, buffer); int allocDescriptorsLen = UdfHelper.Get32(172, buffer); if ((extendedAttrLen & 3) != 0) { return false; } int position = 176; if (extendedAttrLen > size - position) { return false; } position += extendedAttrLen; IcbDescriptorType desctType = item.IcbTag.DescriptorType; if (allocDescriptorsLen > size - position) { return false; } if (desctType == IcbDescriptorType.Inline) { // If the file data is inline, read it in now since we have it. item.IsInline = true; item.InlineData = UdfHelper.Readbytes(position, buffer, allocDescriptorsLen); } else { // Otherwise read the information about where the file is located for later. item.IsInline = false; item.InlineData = new byte[0]; if ((desctType != IcbDescriptorType.Short) && (desctType != IcbDescriptorType.Long)) { return false; } for (int index = 0; index < allocDescriptorsLen;) { FileExtent extent = new FileExtent(); if (desctType == IcbDescriptorType.Short) { if (index + 8 > allocDescriptorsLen) { return false; } ShortAllocationDescriptor sad = new ShortAllocationDescriptor(); sad.Parse(position + index, buffer); extent.Position = sad.Position; extent.Length = sad.Length; extent.PartitionReference = lad.Location.PartitionReference; index += 8; } else { if (index + 16 > allocDescriptorsLen) { return false; } LongAllocationDescriptor ladNew = new LongAllocationDescriptor(); ladNew.Parse(position + index, buffer); extent.Position = ladNew.Location.Position; extent.PartitionReference = ladNew.Location.PartitionReference; extent.Length = ladNew.Length; index += 16; } item.Extents.Add(extent); } } if (item.IcbTag.IsDirectory) { if (!item.CheckChunkSizes() || !this.CheckItemExtents(volumeIndex, item)) { return false; } buffer = new byte[0]; if (!this.ReadFromFile(volumeIndex, ref item, ref buffer)) { return false; } item._size = 0; item.Extents.Clear(); size = buffer.Length; int processedTotal = 0; int processedCur = -1; while (processedTotal < size || processedCur == 0) { UdfFileInformation fileId = new UdfFileInformation(); fileId.Parse(processedTotal, buffer, (size - processedTotal), ref processedCur); if (!fileId.IsItLinkParent) { // Recursively read the contentst of the drirectory UdfRecord fileItem = new UdfRecord(); fileItem.Id = fileId.Identifier; if (fileItem.Id.Data != null) { this.fileNameLengthTotal += fileItem.Id.Data.Length; } if (this.fileNameLengthTotal > MaxFileNameLength) { return false; } fileItem._Parent = item; item.Subitems.Add(fileItem); if (item.Subitems.Count > MaxFiles) { return false; } this.ReadRecord(fileItem, volumeIndex, fileId.Icb, numRecurseAllowed); } processedTotal += processedCur; } } else { if (item.Extents.Count > MaxExtents - this.numExtents) { return false; } this.numExtents += item.Extents.Count; if (item.InlineData.Length > MaxInlineExtentsSize - this.inlineExtentsSize) { return false; } this.inlineExtentsSize += item.InlineData.Length; } this.itemCount++; return true; }
/// <summary> /// Reads the file and directory structure from the image. /// </summary> /// <returns>Returns true if the file system is valid.</returns> private bool ReadFileStructure() { foreach (var volume in this.LogicalVolumes) { // Ensure the volume and parittion are valid. if (!this.ValidateVolumePartition(volume)) { return false; } int volIndex = this.LogicalVolumes.IndexOf(volume); LongAllocationDescriptor nextExtent = volume.FileSetLocation; if (nextExtent.Length < VirtualSectorSize) { return false; } byte[] buffer = new byte[nextExtent.Length]; this.ReadData(volIndex, nextExtent, buffer); VolumeTag tag = new VolumeTag(); tag.Parse(0, buffer, buffer.Length); if (tag.Identifier != (int)VolumeDescriptorType.FileSet) { return false; } UdfFileSet fs = new UdfFileSet(); fs.RecordingTime.Parse(16, buffer); fs.RootDirICB.Parse(400, buffer); volume.FileSet = fs; if (!this.ReadRecord(this.RootDirectory as UdfRecord, volIndex, fs.RootDirICB, MaxRecurseLevels)) { return false; } } return true; }
/// <summary> /// Reads the Anchor Volume pointer from the image. /// </summary> /// <returns>Returns true if the pointer was found.</returns> private UdfFileExtent ReadAnchorVolumePointer() { UdfFileExtent result = null; byte[] buffer = new byte[SectorSize]; this.stream.Seek(-buffer.Length, (int)SeekOrigin.End, IntPtr.Zero); if (!this.stream.ReadSafe(buffer, buffer.Length)) { return result; } VolumeTag tag = new VolumeTag(); if (tag.Parse(0, buffer, buffer.Length) && tag.Identifier == (short)VolumeDescriptorType.AnchorVolumePtr) { result = new UdfFileExtent(); result.Parse(16, buffer); } return result; }