Exemple #1
0
 /// <summary>
 /// Reads and parses the <c>debian-binary</c> file in the Debian archive.
 /// </summary>
 /// <param name="archive">
 /// The archive to update with the data read from the <c>debian-binary</c> file.
 /// </param>
 /// <param name="package">
 /// The package to update.
 /// </param>
 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);
         }
 }
Exemple #2
0
 public static void WriteDebPackage(
     List <ArchiveEntry> archiveEntries,
     Stream tarXzStream,
     Stream targetStream,
     DebPackage pkg)
 {
     ArFileCreator.WriteMagic(targetStream);
     ArFileCreator.WriteEntry(targetStream, "debian-binary", ArFileMode, pkg.PackageFormatVersion + "\n");
     WriteControl(targetStream, pkg, archiveEntries);
     ArFileCreator.WriteEntry(targetStream, "data.tar.xz", ArFileMode, tarXzStream);
 }
        /// <summary>
        /// Reads a <see cref="DebPackage"/> from a <see cref="Stream"/>.
        /// </summary>
        /// <param name="stream">
        /// The <see cref="Stream"/> from which to read the package.
        /// </param>
        /// <returns>
        /// A <see cref="DebPackage"/> which represents the package.
        /// </returns>
        public static async Task <DebPackage> Read(Stream stream)
        {
            DebPackage package = new DebPackage();

            using (ArFile archive = new ArFile(stream, leaveOpen: true))
            {
                while (archive.Read())
                {
                    if (archive.FileName == "debian-binary")
                    {
                        await ReadDebianBinary(archive, package);
                    }
                    else if (archive.FileName == "control.tar.gz")
                    {
                        await ReadControlArchive(archive, package);
                    }
                }
            }

            return(package);
        }
Exemple #4
0
        private static void WriteControl(Stream targetStream, DebPackage pkg, List <ArchiveEntry> entries)
        {
            var controlTar = new MemoryStream();

            WriteControlEntry(controlTar, "./");
            WriteControlEntry(
                controlTar,
                "./control",
                string.Join("\n", pkg.ControlFile
                            .OrderByDescending(x => x.Key == "Package").ThenBy(x => x.Key)
                            .Select(x => $"{x.Key}: {x.Value}")) + "\n");

            WriteControlEntry(
                controlTar,
                "./md5sums",
                string.Join("\n", pkg.Md5Sums.Select(x => $"{x.Value}  {x.Key}")) + "\n");

            var execMode = LinuxFileMode.S_IRUSR | LinuxFileMode.S_IWUSR | LinuxFileMode.S_IXUSR |
                           LinuxFileMode.S_IRGRP | LinuxFileMode.S_IROTH;

            if (!string.IsNullOrWhiteSpace(pkg.PreInstallScript))
            {
                WriteControlEntry(controlTar, "./preinst", $"#!/bin/sh\n{pkg.PreInstallScript}\n", execMode);
            }

            if (!string.IsNullOrWhiteSpace(pkg.PostInstallScript))
            {
                WriteControlEntry(controlTar, "./postinst", $"#!/bin/sh\n{pkg.PostInstallScript}\n", execMode);
            }

            if (!string.IsNullOrWhiteSpace(pkg.PreRemoveScript))
            {
                WriteControlEntry(controlTar, "./prerm", $"#!/bin/sh\n{pkg.PreRemoveScript}\n", execMode);
            }

            if (!string.IsNullOrWhiteSpace(pkg.PostRemoveScript))
            {
                WriteControlEntry(controlTar, "./postrm", $"#!/bin/sh\n{pkg.PostRemoveScript}\n", execMode);
            }

            var confFiles = entries
                            .Where(e => e.Mode.HasFlag(LinuxFileMode.S_IFREG) && e.TargetPath.StartsWith("/etc/"))
                            .Select(e => e.TargetPath).ToList();

            if (confFiles.Any())
            {
                WriteControlEntry(controlTar, "./conffiles", string.Join("\n", confFiles) + "\n");
            }

            TarFileCreator.WriteTrailer(controlTar);
            controlTar.Seek(0, SeekOrigin.Begin);

            var controlTarGz = new MemoryStream();

            using (var gzStream = new GZipStream(controlTarGz, CompressionMode.Compress, true))
            {
                controlTar.CopyTo(gzStream);
            }

            controlTarGz.Seek(0, SeekOrigin.Begin);
            ArFileCreator.WriteEntry(targetStream, "control.tar.gz", ArFileMode, controlTarGz);
        }
Exemple #5
0
        public static DebPackage BuildDebPackage(
            List <ArchiveEntry> archiveEntries,
            string name,
            string description,
            string maintainer,
            string version,
            string arch,
            bool createUser,
            string userName,
            bool installService,
            string serviceName,
            string prefix,
            string section,
            string priority,
            string homepage,
            string preInstallScript,
            string postInstallScript,
            string preRemoveScript,
            string postRemoveScript,
            IEnumerable <string> additionalDependencies,
            Action <DebPackage> additionalMetadata)
        {
            var pkg = new DebPackage
            {
                Md5Sums = archiveEntries.Where(e => e.Md5Hash != null)
                          .ToDictionary(
                    e => e.TargetPath.TrimStart('.', '/'),
                    e => BitConverter.ToString(e.Md5Hash).ToLower().Replace("-", string.Empty)),
                PackageFormatVersion = new Version(2, 0),
                ControlFile          = new Dictionary <string, string>
                {
                    ["Package"]        = name,
                    ["Version"]        = version,
                    ["Architecture"]   = arch,
                    ["Maintainer"]     = maintainer,
                    ["Description"]    = description,
                    ["Installed-Size"] = (archiveEntries.Sum(e => e.FileSize) / 1024).ToString()
                }
            };

            if (!string.IsNullOrEmpty(section))
            {
                pkg.ControlFile["Section"] = section;
            }

            if (!string.IsNullOrEmpty(priority))
            {
                pkg.ControlFile["Priority"] = priority;
            }

            if (!string.IsNullOrEmpty(homepage))
            {
                pkg.ControlFile["Homepage"] = homepage;
            }

            if (createUser)
            {
                // Add the user and group, under which the service runs.
                // These users are never removed because UIDs are re-used on Linux.
                pkg.PreInstallScript += $"/usr/sbin/groupadd -r {userName} 2>/dev/null || :\n" +
                                        $"/usr/sbin/useradd -g {userName} -s /sbin/nologin -r -d {prefix} {userName} 2>/dev/null || :\n";
            }

            if (installService)
            {
                // Install and activate the service.
                pkg.PostInstallScript += $"systemctl daemon-reload\n";
                pkg.PostInstallScript += $"systemctl enable --now {serviceName}.service\n";
                pkg.PreRemoveScript   += $"systemctl --no-reload disable --now {serviceName}.service\n";
            }

            // Remove all directories marked as such (these are usually directories which contain temporary files)
            foreach (var entryToRemove in archiveEntries.Where(e => e.RemoveOnUninstall))
            {
                pkg.PostRemoveScript += $"/bin/rm -rf {entryToRemove.TargetPath}\n";
            }

            if (!string.IsNullOrEmpty(preInstallScript))
            {
                pkg.PreInstallScript += preInstallScript;

                if (!preInstallScript.EndsWith("\n"))
                {
                    pkg.PreInstallScript += "\n";
                }
            }

            if (!string.IsNullOrEmpty(postInstallScript))
            {
                pkg.PostInstallScript += postInstallScript;

                if (!postInstallScript.EndsWith("\n"))
                {
                    pkg.PostInstallScript += "\n";
                }
            }

            if (!string.IsNullOrEmpty(preRemoveScript))
            {
                pkg.PreRemoveScript += preRemoveScript;

                if (!preRemoveScript.EndsWith("\n"))
                {
                    pkg.PreRemoveScript += "\n";
                }
            }

            if (!string.IsNullOrEmpty(postRemoveScript))
            {
                pkg.PostRemoveScript += postRemoveScript;

                if (!postRemoveScript.EndsWith("\n"))
                {
                    pkg.PostRemoveScript += "\n";
                }
            }

            if (additionalDependencies != null)
            {
                pkg.ControlFile["Depends"] = string.Join(", ", additionalDependencies);
            }

            additionalMetadata?.Invoke(pkg);

            return(pkg);
        }
        private static async Task ReadControlArchive(ArFile archive, DebPackage package)
        {
            package.ControlExtras = new Dictionary <string, DebPackageControlFileData>();
            package.Md5Sums       = new Dictionary <string, string>();
            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":
                            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 = await sums.ReadLineAsync()) != 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;
                            }
                        }
                    }
        }
        public static void BuildDebPackage(
            List <ArchiveEntry> archiveEntries,
            Stream tarXzStream,
            string name,
            string description,
            string maintainer,
            string version,
            string arch,
            bool createUser,
            string userName,
            bool installService,
            string serviceName,
            string prefix,
            IEnumerable <PackageDependency> additionalDependencies,
            Action <DebPackage> additionalMetadata,
            Stream targetStream)
        {
            var pkg = new DebPackage
            {
                Md5Sums = archiveEntries.Where(e => e.Md5Hash != null)
                          .ToDictionary(
                    e => e.TargetPath.TrimStart('.', '/'),
                    e => BitConverter.ToString(e.Md5Hash).ToLower().Replace("-", string.Empty)),
                PackageFormatVersion = new Version(2, 0),
                ControlFile          = new Dictionary <string, string>
                {
                    ["Package"]      = name,
                    ["Version"]      = version,
                    ["Architecture"] = arch,
                    ["Maintainer"]   = maintainer,
                    ["Description"]  = description
                }
            };

            if (createUser)
            {
                // Add the user and group, under which the service runs.
                // These users are never removed because UIDs are re-used on Linux.
                pkg.PreInstallScript += $"/usr/sbin/groupadd -r {userName} 2>/dev/null || :\n" +
                                        $"/usr/sbin/useradd -g {userName} -s /sbin/nologin -r -d {prefix} {userName} 2>/dev/null || :\n";
            }

            if (installService)
            {
                // Install and activate the service.
                pkg.PostInstallScript += $"systemctl reload";
                pkg.PostInstallScript += $"systemctl enable --now {serviceName}.service";
                pkg.PreRemoveScript   += $"systemctl --no-reload disable --now {serviceName}.service";
            }

            // Remove all directories marked as such (these are usually directories which contain temporary files)
            foreach (var entryToRemove in archiveEntries.Where(e => e.RemoveOnUninstall))
            {
                pkg.PostRemoveScript += $"/usr/bin/rm -rf {entryToRemove.TargetPath}\n";
            }

            // Dependency list from https://github.com/dotnet/dotnet-docker/blob/master/2.0/runtime-deps/jessie/amd64/Dockerfile
            string libicu = string.Join(" | ", Enumerable.Range(40, 60).Select(n => "libicu" + n));
            string deps   = "libc6, libcurl3, libgcc1, libgssapi-krb5-2, liblttng-ust0, libssl1.0.0, libstdc++6, libunwind8, libuuid1, zlib1g, " +
                            libicu;

            if (additionalDependencies != null)
            {
                foreach (var dependency in additionalDependencies)
                {
                    deps += ", " + dependency;
                }
            }

            pkg.ControlFile["Depends"] = deps;

            additionalMetadata?.Invoke(pkg);

            ArFileCreator.WriteMagic(targetStream);
            ArFileCreator.WriteEntry(targetStream, "debian-binary", ArFileMode, pkg.PackageFormatVersion + "\n");
            WriteControl(targetStream, pkg, archiveEntries);
            ArFileCreator.WriteEntry(targetStream, "data.tar.xz", ArFileMode, tarXzStream);
        }