Beispiel #1
0
 private void ReadFiles(ByteImageReader rdr, ArArchive archive)
 {
     for (; ;)
     {
         var header = ArFileHeader.Load(rdr);
         if (header == null)
         {
             return;
         }
         ReadFile(header, rdr, archive);
     }
 }
Beispiel #2
0
        private void ReadFile(ArFileHeader fileHeader, ByteImageReader rdr, ArArchive archive)
        {
            if (!int.TryParse(fileHeader.FileSize, out int dataSize))
            {
                throw new BadImageFormatException("Invalid archive file header.");
            }
            if (dataSize + rdr.Offset > rdr.Bytes.Length)
            {
                throw new BadImageFormatException("The archive file is corrupt.");
            }

            string name = fileHeader.Name;

            if (name.StartsWith("// "))
            {
                throw new NotImplementedException("Extended file names not implemented yet.");
            }
            else if (name.StartsWith("/ ") || name.StartsWith("__.SYMDEF"))
            {
                // System V symbol lookup table.
                var symbolData = rdr.ReadBytes(dataSize);
                ReadSymbolTable(symbolData);
                return;
            }
            else if (name.StartsWith("#1/ "))
            {
                // File name length follows #1/ as decimal digits.
                // This variant is used by Mac and some versions of BSD.
                var  fileNameLength = Convert.ToInt32(name + 3);
                long fileDataOffset = rdr.Offset + fileNameLength;
                name = Encoding.ASCII.GetString(rdr.ReadBytes(fileNameLength));
                if (dataSize > fileNameLength)
                {
                    // The length of the name is included in the dataSize.
                    dataSize -= fileNameLength;
                }
                rdr.Offset = fileDataOffset;
            }
            else
            {
                // Ordinary short name
                char[] charsToTrim = { '/', ' ' };
                name = name.TrimEnd(charsToTrim);
            }

            archive.AddFile(name, (a, p, name) => new ArFile(a, p, name, rdr, rdr.Offset, dataSize));
            rdr.Offset += dataSize;
            AlignReader(rdr);
        }
Beispiel #3
0
        private static async Task ReadDebAsync(
            string debPath,
            string outputDir,
            Func <string, string> getEntryPath,
            bool shouldExtract)
        {
            // Debian packages (.deb) are "ar" archives with three files.
            //
            // 8 bytes for signature (should be "!<arch>\n")
            //
            // Each section has the following header:
            //  - 16 bytes for file identifier (ASCII)
            //  - 12 bytes for file modification timestamp (decimal)
            //  - 6 bytes for owner ID (decimal)
            //  - 6 bytes for group ID (decimal)
            //  - 8 bytes for file mode (octal)
            //  - 10 bytes for file size (decimal)
            //  - 2 bytes for ending characters ("`\n")
            //
            // The three sections are:
            //  - Package Section
            //  - Control Section
            //  - Data Section
            //
            // We only care about the data section and we expect it to be a .tar.xz.
            const int signatureLength = 8;
            const int headerLength    = 16 + 12 + 6 + 6 + 8 + 10 + 2;
            var       buffer          = new byte[headerLength];

            using (var fileStream = new FileStream(debPath, FileMode.Open))
            {
                var read = fileStream.Read(buffer, 0, signatureLength);
                if (read != signatureLength || Encoding.ASCII.GetString(buffer, 0, read) != "!<arch>\n")
                {
                    throw new TorSharpException("The Debian package did not have the expected file signature.");
                }

                read = fileStream.Read(buffer, 0, headerLength);
                var packageSectionHeader = ArFileHeader.Read(buffer);
                if (read != headerLength ||
                    packageSectionHeader.FileSize != 4)
                {
                    throw new TorSharpException("The Debian package did not have the expected package section file header.");
                }
                fileStream.Position += packageSectionHeader.FileSize;

                read = fileStream.Read(buffer, 0, headerLength);
                var controlSectionHeader = ArFileHeader.Read(buffer);
                fileStream.Position += controlSectionHeader.FileSize;

                read = fileStream.Read(buffer, 0, headerLength);
                var dataSectionHeader     = ArFileHeader.Read(buffer);
                var trimmedFileIdentifier = dataSectionHeader.FileIdentifier.TrimEnd();
                if (!trimmedFileIdentifier.EndsWith(".tar.xz"))
                {
                    throw new TorSharpException("The Debian package's data section is expected to be a .tar.xz file.");
                }

                if (fileStream.Position + dataSectionHeader.FileSize != fileStream.Length)
                {
                    throw new TorSharpException("The Debian package's data section is expected to reach the end of the .dev file.");
                }

                if (!shouldExtract)
                {
                    await ReadTarXzAsync(
                        fileStream,
                        outputDir,
                        getEntryPath,
                        shouldExtract : false).ConfigureAwait(false);
                }
                else
                {
                    await ReadTarXzAsync(
                        fileStream,
                        outputDir,
                        getEntryPath,
                        shouldExtract : true).ConfigureAwait(false);
                }
            }
        }