Skip to content

Commit

Permalink
Ref adamhathcock#248. Ref adamhathcock#132. Tar reader support for sy…
Browse files Browse the repository at this point in the history
…mlinks for .NET standard 2 and Posix platforms

Extracts linkname from the tar header, and exposes this on IEntry as the LinkTarget (string) property. If an entry is not a symlink, then that property is null.

Uses Mono.Posix.NETStandard nuget to create a symlink. However, this is only applicable to .NET standard 2.0+. So far, unable to find a nuget that works for older versions.

Also, not sure what to do on Windows.
  • Loading branch information
markfinal committed Nov 1, 2018
1 parent 0941239 commit 192b9c1
Show file tree
Hide file tree
Showing 10 changed files with 55 additions and 10 deletions.
5 changes: 5 additions & 0 deletions src/SharpCompress/Common/Entry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ public abstract class Entry : IEntry
/// </summary>
public abstract string Key { get; }

/// <summary>
/// The target of a symlink entry internal to the Archive. Will be null if not a symlink.
/// </summary>
public abstract string LinkTarget { get; }

/// <summary>
/// The compressed file size
/// </summary>
Expand Down
41 changes: 31 additions & 10 deletions src/SharpCompress/Common/ExtractionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,40 @@ public static void WriteEntryToFile(IEntry entry, string destinationFileName,
ExtractionOptions options,
Action<string, FileMode> openAndWrite)
{
FileMode fm = FileMode.Create;
options = options ?? new ExtractionOptions()
{
Overwrite = true
};

if (!options.Overwrite)
#if NETSTANDARD2_0
if (entry.LinkTarget != null)
{
fm = FileMode.CreateNew;
/*
var parDir = System.IO.Path.GetDirectoryName(destinationFileName);
if (!System.IO.Directory.Exists(parDir))
{
System.IO.Directory.CreateDirectory(parDir);
}
*/
var link = new Mono.Unix.UnixSymbolicLinkInfo(destinationFileName);
if (System.IO.File.Exists(destinationFileName))
{
link.Delete(); // equivalent to ln -s -f
}
link.CreateSymbolicLinkTo(entry.LinkTarget);
}
else
#endif
{
FileMode fm = FileMode.Create;
options = options ?? new ExtractionOptions()
{
Overwrite = true
};

openAndWrite(destinationFileName, fm);
entry.PreserveExtractionOptions(destinationFileName, options);
if (!options.Overwrite)
{
fm = FileMode.CreateNew;
}

openAndWrite(destinationFileName, fm);
entry.PreserveExtractionOptions(destinationFileName, options);
}
}
#endif
}
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/GZip/GZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ internal GZipEntry(GZipFilePart filePart)

public override string Key => _filePart.FilePartName;

public override string LinkTarget => null;

public override long CompressedSize => 0;

public override long Size => 0;
Expand Down
1 change: 1 addition & 0 deletions src/SharpCompress/Common/IEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public interface IEntry
long Crc { get; }
DateTime? CreatedTime { get; }
string Key { get; }
string LinkTarget { get; }
bool IsDirectory { get; }
bool IsEncrypted { get; }
bool IsSplitAfter { get; }
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/Rar/RarEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public abstract class RarEntry : Entry
/// </summary>
public override string Key => FileHeader.FileName;

public override string LinkTarget => null;

/// <summary>
/// The entry last modified time in the archive, if recorded
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/SevenZip/SevenZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ internal SevenZipEntry(SevenZipFilePart filePart)

public override string Key => FilePart.Header.Name;

public override string LinkTarget => null;

public override long CompressedSize => 0;

public override long Size => FilePart.Header.Size;
Expand Down
7 changes: 7 additions & 0 deletions src/SharpCompress/Common/Tar/Headers/TarHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public TarHeader(ArchiveEncoding archiveEncoding)
}

internal string Name { get; set; }
internal string LinkName { get; set; }

//internal int Mode { get; set; }
//internal int UserId { get; set; }
Expand Down Expand Up @@ -98,6 +99,12 @@ internal bool Read(BinaryReader reader)
return false;
}

// for symlinks, additionally read the linkname
if (ReadEntryType(buffer) == EntryType.SymLink)
{
LinkName = ArchiveEncoding.Decode(buffer, 157, 100).TrimNulls();
}

if (ReadEntryType(buffer) == EntryType.LongName)
{
Name = ReadLongName(reader, buffer);
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/Tar/TarEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ internal TarEntry(TarFilePart filePart, CompressionType type)

public override string Key => _filePart.Header.Name;

public override string LinkTarget => _filePart.Header.LinkName;

public override long CompressedSize => _filePart.Header.Size;

public override long Size => _filePart.Header.Size;
Expand Down
2 changes: 2 additions & 0 deletions src/SharpCompress/Common/Zip/ZipEntry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public override CompressionType CompressionType

public override string Key => _filePart.Header.Name;

public override string LinkTarget => null;

public override long CompressedSize => _filePart.Header.CompressedSize;

public override long Size => _filePart.Header.UncompressedSize;
Expand Down
1 change: 1 addition & 0 deletions src/SharpCompress/SharpCompress.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<DefineConstants>$(DefineConstants);NETCORE</DefineConstants>
</PropertyGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
<PackageReference Include="Mono.Posix.NETStandard" Version="1.0.0" />
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.5.0" />
</ItemGroup>
</Project>

0 comments on commit 192b9c1

Please sign in to comment.