Beispiel #1
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);
                }
            }
        }