public CommonVolumeDescriptor(byte[] src, int offset, Encoding enc) : base(src, offset) { CharacterEncoding = enc; SystemIdentifier = IsoUtilities.ReadChars(src, offset + 8, 32, CharacterEncoding); VolumeIdentifier = IsoUtilities.ReadChars(src, offset + 40, 32, CharacterEncoding); VolumeSpaceSize = IsoUtilities.ToUInt32FromBoth(src, offset + 80); VolumeSetSize = IsoUtilities.ToUInt16FromBoth(src, offset + 120); VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 124); LogicalBlockSize = IsoUtilities.ToUInt16FromBoth(src, offset + 128); PathTableSize = IsoUtilities.ToUInt32FromBoth(src, offset + 132); TypeLPathTableLocation = EndianUtilities.ToUInt32LittleEndian(src, offset + 140); OptionalTypeLPathTableLocation = EndianUtilities.ToUInt32LittleEndian(src, offset + 144); TypeMPathTableLocation = Utilities.BitSwap(EndianUtilities.ToUInt32LittleEndian(src, offset + 148)); OptionalTypeMPathTableLocation = Utilities.BitSwap(EndianUtilities.ToUInt32LittleEndian(src, offset + 152)); DirectoryRecord.ReadFrom(src, offset + 156, CharacterEncoding, out RootDirectory); VolumeSetIdentifier = IsoUtilities.ReadChars(src, offset + 190, 318 - 190, CharacterEncoding); PublisherIdentifier = IsoUtilities.ReadChars(src, offset + 318, 446 - 318, CharacterEncoding); DataPreparerIdentifier = IsoUtilities.ReadChars(src, offset + 446, 574 - 446, CharacterEncoding); ApplicationIdentifier = IsoUtilities.ReadChars(src, offset + 574, 702 - 574, CharacterEncoding); CopyrightFileIdentifier = IsoUtilities.ReadChars(src, offset + 702, 739 - 702, CharacterEncoding); AbstractFileIdentifier = IsoUtilities.ReadChars(src, offset + 739, 776 - 739, CharacterEncoding); BibliographicFileIdentifier = IsoUtilities.ReadChars(src, offset + 776, 813 - 776, CharacterEncoding); CreationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 813); ModificationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 830); ExpirationDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 847); EffectiveDateAndTime = IsoUtilities.ToDateTimeFromVolumeDescriptorTime(src, offset + 864); FileStructureVersion = src[offset + 881]; }
public static int ReadFrom(byte[] src, int offset, Encoding enc, out DirectoryRecord record) { int length = src[offset + 0]; record = new DirectoryRecord(); record.ExtendedAttributeRecordLength = src[offset + 1]; record.LocationOfExtent = IsoUtilities.ToUInt32FromBoth(src, offset + 2); record.DataLength = IsoUtilities.ToUInt32FromBoth(src, offset + 10); record.RecordingDateAndTime = IsoUtilities.ToUTCDateTimeFromDirectoryTime(src, offset + 18); record.Flags = (FileFlags)src[offset + 25]; record.FileUnitSize = src[offset + 26]; record.InterleaveGapSize = src[offset + 27]; record.VolumeSequenceNumber = IsoUtilities.ToUInt16FromBoth(src, offset + 28); byte lengthOfFileIdentifier = src[offset + 32]; record.FileIdentifier = IsoUtilities.ReadChars(src, offset + 33, lengthOfFileIdentifier, enc); int padding = (lengthOfFileIdentifier & 1) == 0 ? 1 : 0; int startSystemArea = lengthOfFileIdentifier + padding + 33; int lenSystemArea = length - startSystemArea; if (lenSystemArea > 0) { record.SystemUseData = new byte[lenSystemArea]; Array.Copy(src, offset + startSystemArea, record.SystemUseData, 0, lenSystemArea); } return(length); }
private static DirectoryRecord ReadRootSelfRecord(IsoContext context) { context.DataStream.Position = context.VolumeDescriptor.RootDirectory.LocationOfExtent * context.VolumeDescriptor.LogicalBlockSize + 24; byte[] firstSector = StreamUtilities.ReadExact(context.DataStream, context.VolumeDescriptor.LogicalBlockSize); DirectoryRecord rootSelfRecord; DirectoryRecord.ReadFrom(firstSector, 0, context.VolumeDescriptor.CharacterEncoding, out rootSelfRecord); return(rootSelfRecord); }
private static int WriteMember(BuildDirectoryMember m, string nameOverride, Encoding nameEnc, byte[] buffer, int offset, Dictionary <BuildDirectoryMember, uint> locationTable, Encoding dataEnc, int sectorSize) { DirectoryRecord dr = new DirectoryRecord(); dr.FileIdentifier = m.PickName(nameOverride, nameEnc); dr.LocationOfExtent = locationTable[m]; dr.DataLength = (uint)m.GetDataSize(dataEnc); dr.RecordingDateAndTime = m.CreationTime; dr.Flags = m is BuildDirectoryInfo ? FileFlags.Directory : FileFlags.None; return(dr.WriteTo(buffer, offset, nameEnc)); }
private static void InitializeSusp(IsoContext context, DirectoryRecord rootSelfRecord) { // Stage 1 - SUSP present? List <SuspExtension> extensions = new List <SuspExtension>(); if (!SuspRecords.DetectSharingProtocol(rootSelfRecord.SystemUseData, 0)) { context.SuspExtensions = new List <SuspExtension>(); context.SuspDetected = false; return; } context.SuspDetected = true; SuspRecords suspRecords = new SuspRecords(context, rootSelfRecord.SystemUseData, 0); // Stage 2 - Init general SUSP params SharingProtocolSystemUseEntry spEntry = (SharingProtocolSystemUseEntry)suspRecords.GetEntries(null, "SP")[0]; context.SuspSkipBytes = spEntry.SystemAreaSkip; // Stage 3 - Init extensions List <SystemUseEntry> extensionEntries = suspRecords.GetEntries(null, "ER"); if (extensionEntries != null) { foreach (ExtensionSystemUseEntry extension in extensionEntries) { switch (extension.ExtensionIdentifier) { case "RRIP_1991A": case "IEEE_P1282": case "IEEE_1282": extensions.Add(new RockRidgeExtension(extension.ExtensionIdentifier)); context.RockRidgeIdentifier = extension.ExtensionIdentifier; break; default: extensions.Add(new GenericSuspExtension(extension.ExtensionIdentifier)); break; } } } else if (suspRecords.GetEntries(null, "RR") != null) { // Some ISO creators don't add the 'ER' record for RockRidge, but write the (legacy) // RR record anyway extensions.Add(new RockRidgeExtension("RRIP_1991A")); context.RockRidgeIdentifier = "RRIP_1991A"; } context.SuspExtensions = extensions; }
public ReaderDirectory(IsoContext context, ReaderDirEntry dirEntry) : base(context, dirEntry) { byte[] buffer = new byte[context.SectorSize]; Stream extent = new ExtentStream(_context.DataStream, dirEntry.Record.LocationOfExtent, uint.MaxValue, 0, 0, context.SectorSize); _records = new List <ReaderDirEntry>(); uint totalLength = dirEntry.Record.DataLength; uint totalRead = 0; while (totalRead < totalLength) { int bytesRead = (int)Math.Min(buffer.Length, totalLength - totalRead); extent.Seek(24, SeekOrigin.Current); StreamUtilities.ReadExact(extent, buffer, 0, bytesRead); totalRead += (uint)bytesRead; uint pos = 0; while (pos < bytesRead && buffer[pos] != 0) { DirectoryRecord dr; uint length = (uint)DirectoryRecord.ReadFrom(buffer, (int)pos, context.VolumeDescriptor.CharacterEncoding, out dr); if (!IsoUtilities.IsSpecialDirectory(dr)) { ReaderDirEntry childDirEntry = new ReaderDirEntry(_context, dr); if (context.SuspDetected && !string.IsNullOrEmpty(context.RockRidgeIdentifier)) { if (childDirEntry.SuspRecords == null || !childDirEntry.SuspRecords.HasEntry(context.RockRidgeIdentifier, "RE")) { _records.Add(childDirEntry); } } else { _records.Add(childDirEntry); } } else if (dr.FileIdentifier == "\0") { Self = new ReaderDirEntry(_context, dr); } pos += length; } } }
public CommonVolumeDescriptor( VolumeDescriptorType type, byte version, uint volumeSpaceSize, uint pathTableSize, uint typeLPathTableLocation, uint typeMPathTableLocation, uint rootDirExtentLocation, uint rootDirDataLength, DateTime buildTime, Encoding enc, int sectorSize) : base(type, version, sectorSize) { CharacterEncoding = enc; SystemIdentifier = string.Empty; VolumeIdentifier = string.Empty; VolumeSpaceSize = volumeSpaceSize; VolumeSetSize = 1; VolumeSequenceNumber = 1; LogicalBlockSize = (ushort)sectorSize; PathTableSize = pathTableSize; TypeLPathTableLocation = typeLPathTableLocation; ////OptionalTypeLPathTableLocation = 0; TypeMPathTableLocation = typeMPathTableLocation; ////OptionalTypeMPathTableLocation = 0; RootDirectory = new DirectoryRecord(); RootDirectory.ExtendedAttributeRecordLength = 0; RootDirectory.LocationOfExtent = rootDirExtentLocation; RootDirectory.DataLength = rootDirDataLength; RootDirectory.RecordingDateAndTime = buildTime; RootDirectory.Flags = FileFlags.Directory; RootDirectory.FileUnitSize = 0; RootDirectory.InterleaveGapSize = 0; RootDirectory.VolumeSequenceNumber = 1; RootDirectory.FileIdentifier = "\0"; VolumeSetIdentifier = string.Empty; PublisherIdentifier = string.Empty; DataPreparerIdentifier = string.Empty; ApplicationIdentifier = string.Empty; CopyrightFileIdentifier = string.Empty; AbstractFileIdentifier = string.Empty; BibliographicFileIdentifier = string.Empty; CreationDateAndTime = buildTime; ModificationDateAndTime = buildTime; ExpirationDateAndTime = DateTime.MinValue; EffectiveDateAndTime = buildTime; FileStructureVersion = 1; // V1 }
internal uint GetDirectoryRecordSize(Encoding enc) { return(DirectoryRecord.CalcLength(PickName(null, enc), enc)); }
/// <summary> /// Initializes a new instance of the VfsCDReader class. /// </summary> /// <param name="data">The stream to read the ISO image from.</param> /// <param name="variantPriorities">Which possible file system variants to use, and with which priority.</param> /// <param name="hideVersions">Hides version numbers (e.g. ";1") from the end of files.</param> /// <remarks> /// <para> /// The implementation considers each of the file system variants in <c>variantProperties</c> and selects /// the first which is determined to be present. In this example Joliet, then Rock Ridge, then vanilla /// Iso9660 will be considered: /// </para> /// <code lang="cs"> /// VfsCDReader(stream, new Iso9660Variant[] {Joliet, RockRidge, Iso9660}, true); /// </code> /// <para>The Iso9660 variant should normally be specified as the final entry in the list. Placing it earlier /// in the list will effectively mask later items and not including it may prevent some ISOs from being read.</para> /// </remarks> public VfsCDReader(Stream data, Iso9660Variant[] variantPriorities, bool hideVersions, int sectorSize) : base(new DiscFileSystemOptions()) { _data = data; _sectorSize = sectorSize; _hideVersions = hideVersions; long vdpos = _sectorSize * 16; // Skip lead-in byte[] buffer = new byte[_sectorSize]; long pvdPos = 0; long svdPos = 0; BaseVolumeDescriptor bvd; do { data.Position = vdpos; int numRead = data.Read(buffer, 0, _sectorSize); if (numRead != _sectorSize) { break; } var offset = 24; bvd = new BaseVolumeDescriptor(buffer, offset); if (bvd.StandardIdentifier != BaseVolumeDescriptor.Iso9660StandardIdentifier) { throw new InvalidFileSystemException("Volume is not ISO-9660"); } switch (bvd.VolumeDescriptorType) { case VolumeDescriptorType.Boot: _bootVolDesc = new BootVolumeDescriptor(buffer, offset); if (_bootVolDesc.SystemId != BootVolumeDescriptor.ElToritoSystemIdentifier) { _bootVolDesc = null; } break; case VolumeDescriptorType.Primary: // Primary Vol Descriptor pvdPos = vdpos; break; case VolumeDescriptorType.Supplementary: // Supplementary Vol Descriptor svdPos = vdpos; break; case VolumeDescriptorType.Partition: // Volume Partition Descriptor break; case VolumeDescriptorType.SetTerminator: // Volume Descriptor Set Terminator break; } vdpos += _sectorSize; } while (bvd.VolumeDescriptorType != VolumeDescriptorType.SetTerminator); ActiveVariant = Iso9660Variant.None; foreach (Iso9660Variant variant in variantPriorities) { switch (variant) { case Iso9660Variant.Joliet: if (svdPos != 0) { data.Position = svdPos; data.Read(buffer, 0, _sectorSize); SupplementaryVolumeDescriptor volDesc = new SupplementaryVolumeDescriptor(buffer, 0); Context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data }; RootDirectory = new ReaderDirectory(Context, new ReaderDirEntry(Context, volDesc.RootDirectory)); ActiveVariant = Iso9660Variant.Iso9660; } break; case Iso9660Variant.RockRidge: case Iso9660Variant.Iso9660: if (pvdPos != 0) { data.Position = pvdPos + 24; data.Read(buffer, 0, _sectorSize); PrimaryVolumeDescriptor volDesc = new PrimaryVolumeDescriptor(buffer, 0); volDesc.LogicalBlockSize = 2352; IsoContext context = new IsoContext(_sectorSize) { VolumeDescriptor = volDesc, DataStream = _data }; DirectoryRecord rootSelfRecord = ReadRootSelfRecord(context); InitializeSusp(context, rootSelfRecord); if (variant == Iso9660Variant.Iso9660 || (variant == Iso9660Variant.RockRidge && !string.IsNullOrEmpty(context.RockRidgeIdentifier))) { Context = context; RootDirectory = new ReaderDirectory(context, new ReaderDirEntry(context, rootSelfRecord)); ActiveVariant = variant; } } break; } if (ActiveVariant != Iso9660Variant.None) { break; } } if (ActiveVariant == Iso9660Variant.None) { throw new IOException("None of the permitted ISO9660 file system variants was detected"); } }
internal static bool IsSpecialDirectory(DirectoryRecord r) { return(r.FileIdentifier == "\0" || r.FileIdentifier == "\x01"); }
public ReaderDirEntry(IsoContext context, DirectoryRecord dirRecord) { _context = context; _record = dirRecord; _fileName = _record.FileIdentifier; bool rockRidge = !string.IsNullOrEmpty(_context.RockRidgeIdentifier); if (context.SuspDetected && _record.SystemUseData != null) { SuspRecords = new SuspRecords(_context, _record.SystemUseData, 0); } if (rockRidge && SuspRecords != null) { // The full name is taken from this record, even if it's a child-link record List <SystemUseEntry> nameEntries = SuspRecords.GetEntries(_context.RockRidgeIdentifier, "NM"); StringBuilder rrName = new StringBuilder(); if (nameEntries != null && nameEntries.Count > 0) { foreach (PosixNameSystemUseEntry nameEntry in nameEntries) { rrName.Append(nameEntry.NameData); } _fileName = rrName.ToString(); } // If this is a Rock Ridge child link, replace the dir record with that from the 'self' record // in the child directory. ChildLinkSystemUseEntry clEntry = SuspRecords.GetEntry <ChildLinkSystemUseEntry>(_context.RockRidgeIdentifier, "CL"); if (clEntry != null) { _context.DataStream.Position = clEntry.ChildDirLocation * _context.VolumeDescriptor.LogicalBlockSize; byte[] firstSector = StreamUtilities.ReadExact(_context.DataStream, _context.VolumeDescriptor.LogicalBlockSize); DirectoryRecord.ReadFrom(firstSector, 0, _context.VolumeDescriptor.CharacterEncoding, out _record); if (_record.SystemUseData != null) { SuspRecords = new SuspRecords(_context, _record.SystemUseData, 0); } } } LastAccessTimeUtc = _record.RecordingDateAndTime; LastWriteTimeUtc = _record.RecordingDateAndTime; CreationTimeUtc = _record.RecordingDateAndTime; if (rockRidge && SuspRecords != null) { FileTimeSystemUseEntry tfEntry = SuspRecords.GetEntry <FileTimeSystemUseEntry>(_context.RockRidgeIdentifier, "TF"); if (tfEntry != null) { if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Access) != 0) { LastAccessTimeUtc = tfEntry.AccessTime; } if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Modify) != 0) { LastWriteTimeUtc = tfEntry.ModifyTime; } if ((tfEntry.TimestampsPresent & FileTimeSystemUseEntry.Timestamps.Creation) != 0) { CreationTimeUtc = tfEntry.CreationTime; } } } }