using Packaging.Targets.IO; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; namespace Packaging.Targets.Deb { /// /// Reads objects from a . /// internal static class DebPackageReader { /// /// Reads a from a . /// /// /// The from which to read the package. /// /// /// A which represents the package. /// internal static DebPackage Read(Stream stream) { DebPackage package = new DebPackage(); using (ArFile archive = new ArFile(stream, leaveOpen: true)) { while (archive.Read()) { if (archive.FileName == "debian-binary") { ReadDebianBinary(archive, package); } else if (archive.FileName == "control.tar.gz") { ReadControlArchive(archive, package); } } } return package; } internal static Stream GetPayloadStream(Stream stream) { using (ArFile archive = new ArFile(stream, leaveOpen: true)) { while (archive.Read()) { if (archive.FileName.StartsWith("data.tar.")) { var ext = Path.GetExtension(archive.FileName); if (ext == ".gz") { return new GZipDecompressor(archive.Open(), false); } if (ext == ".xz") { // For some reason it complains about corrupted data when we try to read using smaller chunks var payload = new MemoryStream(); using (var xz = new XZInputStream(archive.Open())) { xz.CopyTo(payload); payload.Seek(0, SeekOrigin.Begin); return payload; } } throw new InvalidDataException("Don't know how to decompress " + archive.FileName); } } throw new InvalidDataException("data.tar.?? not found"); } } /// /// Reads and parses the debian-binary file in the Debian archive. /// /// /// The archive to update with the data read from the debian-binary file. /// /// /// The package to update. /// private static void ReadDebianBinary(ArFile archive, DebPackage package) { using (Stream stream = archive.Open()) using (StreamReader reader = new StreamReader(stream)) { var content = reader.ReadToEnd(); package.PackageFormatVersion = new Version(content); } } private static void ReadControlArchive(ArFile archive, DebPackage package) { package.ControlExtras = new Dictionary(); package.Md5Sums = new Dictionary(); using (Stream stream = archive.Open()) using (GZipDecompressor decompressedStream = new GZipDecompressor(stream, leaveOpen: true)) using (TarFile tarFile = new TarFile(decompressedStream, leaveOpen: true)) { while (tarFile.Read()) { switch (tarFile.FileName) { case "./control": using (Stream controlFile = tarFile.Open()) { package.ControlFile = ControlFileParser.Read(controlFile); } break; case "./md5sums": using (var sums = new StreamReader(tarFile.Open())) { string line; while ((line = sums.ReadLine()) != null) { var s = line.Split(new[] { " " }, 2, StringSplitOptions.None); package.Md5Sums[s[1]] = s[0]; } } break; case "./preinst": package.PreInstallScript = tarFile.ReadAsUtf8String(); break; case "./postinst": package.PostInstallScript = tarFile.ReadAsUtf8String(); break; case "./prerm": package.PreRemoveScript = tarFile.ReadAsUtf8String(); break; case "./postrm": package.PostRemoveScript = tarFile.ReadAsUtf8String(); break; case "./": tarFile.Skip(); break; default: package.ControlExtras[tarFile.FileName] = new DebPackageControlFileData { Mode = tarFile.FileHeader.FileMode, Contents = tarFile.ReadAsUtf8String() }; break; } } } } } }