/// <inheritdoc/> public override void Extract(IBuilder builder, Stream stream, string?subDir = null) { var symlinks = new List <(string path, string target)>(); var hardlinks = new List <(string path, string existingPath, bool executable)>(); try { using var tarStream = new TarInputStream(stream, Encoding.UTF8) { IsStreamOwner = false }; while (tarStream.GetNextEntry() is {} entry) { Handler.CancellationToken.ThrowIfCancellationRequested(); string?relativePath = NormalizePath(entry.Name, subDir); if (string.IsNullOrEmpty(relativePath)) { continue; } switch (entry.TarHeader.TypeFlag) { case TarHeader.LF_SYMLINK: symlinks.Add((relativePath, entry.TarHeader.LinkName)); break; case TarHeader.LF_LINK: string?targetPath = NormalizePath(entry.TarHeader.LinkName, subDir); if (string.IsNullOrEmpty(targetPath)) { throw new IOException($"The hardlink '{relativePath}' in the archive points to a non-existent file '{entry.TarHeader.LinkName}'."); } hardlinks.Add((relativePath, targetPath, IsExecutable(entry))); break; case TarHeader.LF_DIR: builder.AddDirectory(relativePath); break; case TarHeader.LF_NORMAL or TarHeader.LF_OLDNORM: builder.AddFile(relativePath, tarStream.WithLength(entry.Size), entry.TarHeader.ModTime, IsExecutable(entry)); break; default: throw new NotSupportedException($"Archive entry '{entry.Name}' has unsupported type: {entry.TarHeader.TypeFlag}"); } } foreach ((string path, string target) in symlinks) { builder.AddSymlink(path, target); } foreach ((string path, string existingPath, bool executable) in hardlinks) builder.AddHardlink(path, existingPath, executable); } #region Error handling catch (Exception ex) when(ex is SharpZipBaseException or InvalidDataException or ArgumentOutOfRangeException or IndexOutOfRangeException or { Message: "Data Error" })
/// <inheritdoc/> public void AddHardlink(string path, string target, bool executable = false) => _underlyingBuilder.AddHardlink(Path.Combine(_prefix, path), Path.Combine(_prefix, target), executable);