/// <summary> /// Reads a record from the file system. /// </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 item and all sub items were read correctly.</returns> private bool ReadRecord(UdfRecord item, int volumeIndex, LongAllocationDescriptor lad, int numRecurseAllowed) { if (numRecurseAllowed-- == 0) { return(false); } LogicalVolume vol = this.LogicalVolumes[volumeIndex]; Partition partition = this.Partitions[vol.PartitionMaps[lad.Location.PartitionReference].PartitionIndex]; int key = lad.Location.Position; if (partition.Map.ContainsKey(key)) { // Item already in the map, just look it up instead of reading it from the image. item.VolumeIndex = partition.Map[key].VolumeIndex; item.PartitionIndex = partition.Map[key].PartitionIndex; item.Extents = partition.Map[key].Extents; item._size = partition.Map[key]._size; item.Key = key; } else { item.VolumeIndex = volumeIndex; item.PartitionIndex = vol.PartitionMaps[lad.Location.PartitionReference].PartitionIndex; item.Key = key; if (!partition.Map.Set(key, item) || !this.ReadRecordData(item, volumeIndex, lad, numRecurseAllowed)) { return(false); } } return(true); }
/// <summary> /// Validates that the volume has a valid partition. /// </summary> /// <param name="volume">The volume to validate.</param> /// <returns>Returns true if the volume is valid.</returns> private bool ValidateVolumePartition(LogicalVolume volume) { for (int i = 0; i < volume.PartitionMaps.Count; i++) { PartitionMap map = volume.PartitionMaps[0]; bool found = false; foreach (var partition in this.Partitions) { if (partition.Number == map.PartitionNumber) { // partition can only be member of one volume if (partition.VolumeIndex >= 0) { return(false); } // Add cross references between partitions and volumes. map.PartitionNumber = this.Partitions.IndexOf(partition); partition.VolumeIndex = this.LogicalVolumes.IndexOf(volume); found = true; } } if (!found) { return(false); } } return(true); }
/// <summary> /// Reads a logical volume descriptor from the buffer. /// </summary> /// <param name="buffer">The buffer to read the data from.</param> /// <returns>Returns true if the descriptor is valid.</returns> private bool ReadLogicalDescriptor(byte[] buffer) { LogicalVolume volume = new LogicalVolume(); volume.Id.Parse(84, buffer); volume.BlockSize = UdfHelper.Get32(212, buffer); if (volume.BlockSize < VirtualSectorSize || volume.BlockSize > MaxExtents) { return(false); } volume.FileSetLocation.Parse(248, buffer); int numPartitionMaps = UdfHelper.Get32(268, buffer); if (numPartitionMaps > MaxPartitions) { return(false); } int position = 440; for (int index = 0; index < numPartitionMaps; index++) { if (position + 2 > SectorSize) { return(false); } PartitionMap pm = new PartitionMap(); pm.Type = buffer[position]; byte length = buffer[position + 1]; if (position + length > SectorSize) { return(false); } if (pm.Type == 1) { if (position + 6 > SectorSize) { return(false); } pm.PartitionNumber = UdfHelper.Get16(position + 4, buffer); } else { return(false); } position += length; pm.PartitionIndex = volume.PartitionMaps.Count; volume.PartitionMaps.Add(pm); } this.LogicalVolumes.Add(volume); return(true); }
/// <summary> /// Validates to ensure the extent is in a valid format. /// </summary> /// <param name="volumeIndex">The volume index.</param> /// <param name="partitionReference">The partition reference.</param> /// <param name="blockPosition">The current block position.</param> /// <param name="length">The length of the extent.</param> /// <returns>Returns true if the extent is valid.</returns> private bool CheckExtent(int volumeIndex, int partitionReference, int blockPosition, int length) { LogicalVolume volume = this.LogicalVolumes[volumeIndex]; Partition partition = this.Partitions[volume.PartitionMaps[partitionReference].PartitionIndex]; long offset = ((long)partition.Position << SectorSizeLog) + ((long)blockPosition * volume.BlockSize); return((offset + length) <= (((long)partition.Position + partition.Length) << SectorSizeLog)); }
/// <summary> /// Reads data from the stream. /// </summary> /// <param name="volumeIndex">The volume index of the data.</param> /// <param name="partitionReference">The partition reference.</param> /// <param name="blockPosition">The block position of the data to read.</param> /// <param name="length">The length of the data to read.</param> /// <param name="buffer">The buffer to contain the data.</param> /// <returns>Returns true if the data was read successfully.</returns> private bool ReadData(int volumeIndex, int partitionReference, int blockPosition, int length, byte[] buffer) { if (!this.CheckExtent(volumeIndex, partitionReference, blockPosition, length)) { return(false); } LogicalVolume volume = this.LogicalVolumes[volumeIndex]; Partition partition = this.Partitions[volume.PartitionMaps[partitionReference].PartitionIndex]; this.stream.Seek(((long)partition.Position << SectorSizeLog) + (blockPosition * volume.BlockSize), (int)SeekOrigin.Begin, IntPtr.Zero); return(this.stream.ReadSafe(buffer, length)); }
/// <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); }