diff --git a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs index 57cd5c71..86b56055 100644 --- a/src/SharpCompress/Common/Rar/Headers/FileHeader.cs +++ b/src/SharpCompress/Common/Rar/Headers/FileHeader.cs @@ -109,7 +109,7 @@ private void ReadFromReaderV5(MarkingBinaryReader reader) const ushort FHEXTRA_HASH = 0x02; const ushort FHEXTRA_HTIME = 0x03; // const ushort FHEXTRA_VERSION = 0x04; - // const ushort FHEXTRA_REDIR = 0x05; + const ushort FHEXTRA_REDIR = 0x05; // const ushort FHEXTRA_UOWNER = 0x06; // const ushort FHEXTRA_SUBDATA = 0x07; @@ -120,7 +120,6 @@ private void ReadFromReaderV5(MarkingBinaryReader reader) var type = reader.ReadRarVIntUInt16(); switch (type) { - //TODO case FHEXTRA_CRYPT: // file encryption { @@ -171,11 +170,17 @@ private void ReadFromReaderV5(MarkingBinaryReader reader) // // } // break; - // case FHEXTRA_REDIR: // file system redirection - // { - // - // } - // break; + case FHEXTRA_REDIR: // file system redirection + + { + RedirType = reader.ReadRarVIntByte(); + RedirFlags = reader.ReadRarVIntByte(); + var nn = reader.ReadRarVIntUInt16(); + var bb = reader.ReadBytes(nn); + RedirTargetName = ConvertPathV5(Encoding.UTF8.GetString(bb, 0, bb.Length)); + } + break; + //TODO // case FHEXTRA_UOWNER: // unix owner // { // @@ -189,6 +194,7 @@ private void ReadFromReaderV5(MarkingBinaryReader reader) default: // skip unknown record types to allow new record types to be added in the future + //Console.WriteLine($"unhandled rar header field type {type}"); break; } // drain any trailing bytes of extra record @@ -437,6 +443,12 @@ internal byte[] FileCrc public bool IsSolid { get; private set; } + public byte RedirType { get; private set; } + public bool IsRedir => RedirType != 0; + public byte RedirFlags { get; private set; } + public bool IsRedirDirectory => (RedirFlags & RedirFlagV5.DIRECTORY) != 0; + public string RedirTargetName { get; private set; } + // unused for UnpackV1 implementation (limitation) internal size_t WindowSize { get; private set; } diff --git a/src/SharpCompress/Common/Rar/Headers/Flags.cs b/src/SharpCompress/Common/Rar/Headers/Flags.cs index 3414d1a3..990dbc99 100644 --- a/src/SharpCompress/Common/Rar/Headers/Flags.cs +++ b/src/SharpCompress/Common/Rar/Headers/Flags.cs @@ -157,3 +157,17 @@ internal static class EndArchiveFlagsV5 { public const ushort HAS_NEXT_VOLUME = 0x0001; } + +internal static class RedirTypeV5 +{ + public const byte UNIX_SYMLINK = 0x0001; + public const byte WIN_SYMLINK = 0x0002; + public const byte WIN_JUNCTION = 0x0003; + public const byte HARD_LINK = 0x0004; + public const byte FILE_COPY = 0x0005; +} + +internal static class RedirFlagV5 +{ + public const byte DIRECTORY = 0x0001; +} diff --git a/src/SharpCompress/Common/Rar/RarEntry.cs b/src/SharpCompress/Common/Rar/RarEntry.cs index 639c9d94..30de1037 100644 --- a/src/SharpCompress/Common/Rar/RarEntry.cs +++ b/src/SharpCompress/Common/Rar/RarEntry.cs @@ -66,6 +66,10 @@ public abstract class RarEntry : Entry public override bool IsSplitAfter => FileHeader.IsSplitAfter; + public bool IsRedir => FileHeader.IsRedir; + + public string RedirTargetName => FileHeader.RedirTargetName; + public override string ToString() => string.Format( "Entry Path: {0} Compressed Size: {1} Uncompressed Size: {2} CRC: {3}", diff --git a/src/SharpCompress/Compressors/Rar/RarStream.cs b/src/SharpCompress/Compressors/Rar/RarStream.cs index 0bc2e054..a1404e49 100644 --- a/src/SharpCompress/Compressors/Rar/RarStream.cs +++ b/src/SharpCompress/Compressors/Rar/RarStream.cs @@ -86,6 +86,11 @@ public override int Read(byte[] buffer, int offset, int count) fetch = false; } _position += outTotal; + if (count > 0 && outTotal == 0 && _position != Length) + { + // sanity check, eg if we try to decompress a redir entry + throw new InvalidOperationException($"unpacked file size does not match header: expected {Length} found {_position}"); + } return outTotal; } diff --git a/src/SharpCompress/Readers/Rar/RarReader.cs b/src/SharpCompress/Readers/Rar/RarReader.cs index a9ddb1fe..ac346262 100644 --- a/src/SharpCompress/Readers/Rar/RarReader.cs +++ b/src/SharpCompress/Readers/Rar/RarReader.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -64,6 +65,11 @@ protected virtual IEnumerable CreateFilePartEnumerableForCurrentEntry( protected override EntryStream GetEntryStream() { + if (Entry.IsRedir) + { + throw new InvalidOperationException("no stream for redirect entry"); + } + var stream = new MultiVolumeReadOnlyStream( CreateFilePartEnumerableForCurrentEntry().Cast(), this