/hg/release/icedtea6-1.9: Backport S6687968, S6541476, S6782079

dbhole at icedtea.classpath.org dbhole at icedtea.classpath.org
Tue Jan 4 06:57:54 PST 2011


changeset 7919aac747ab in /hg/release/icedtea6-1.9
details: http://icedtea.classpath.org/hg/release/icedtea6-1.9?cmd=changeset;node=7919aac747ab
author: Deepak Bhole <dbhole at redhat.com>
date: Tue Jan 04 08:55:53 2011 -0500

	Backport S6687968, S6541476, S6782079

	iTXt chunk handling for png now works correctly.


diffstat:

6 files changed, 4818 insertions(+), 1 deletion(-)
ChangeLog                                             |   14 
Makefile.am                                           |    5 
NEWS                                                  |    3 
patches/openjdk/6541476-png-iTXt-chunk.patch          |  549 ++
patches/openjdk/6687968-pngimagereader_mem_leak.patch |  126 
patches/openjdk/6782079-png_metadata_oom.patch        | 4122 +++++++++++++++++

diffs (truncated from 4859 to 500 lines):

diff -r f06befaad21b -r 7919aac747ab ChangeLog
--- a/ChangeLog	Thu Dec 23 15:52:22 2010 +0100
+++ b/ChangeLog	Tue Jan 04 08:55:53 2011 -0500
@@ -1,4 +1,18 @@ 2010-12-23  Jiri Vanek <jvanek at redhat.co
+2010-12-24  Deepak Bhole <dbhole at redhat.com>
+
+	Backport S6687968, S6541476, S6782079
+	* Makefile.am: Add missing "\" to the patch list, update to include 
+	new patches.
+	* NEWS: Updated.
+	* patches/openjdk/6687968-pngimagereader_mem_leak.patch: Backport to allow
+	S6541476 fix to apply cleanly.
+	* patches/openjdk/6541476-png-iTXt-chunk.patch: Backport to fix iTXt chunk
+	handling for png images. Also addresses RH665355.
+	* patches/openjdk/6782079-png_metadata_oom.patch: Backport to fix
+	potential OOM error when reading metadata on truncated pngs.
+
 2010-12-23  Jiri Vanek <jvanek at redhat.com>
+
 	* NEWS: Updated with rh.bugzilas.
 	* patches/fonts-rhel.patch:repaired rhel 6 fonts configuration.
 
diff -r f06befaad21b -r 7919aac747ab Makefile.am
--- a/Makefile.am	Thu Dec 23 15:52:22 2010 +0100
+++ b/Makefile.am	Tue Jan 04 08:55:53 2011 -0500
@@ -323,7 +323,10 @@ ICEDTEA_PATCHES = \
 	patches/openjdk/6438179-systray_check.patch \
 	patches/openjdk/4356282-opentype.patch \
 	patches/openjdk/6954424-opentype_javadoc.patch \
-	patches/openjdk/6795356-proxylazyvalue-leak.patch
+	patches/openjdk/6795356-proxylazyvalue-leak.patch \
+	patches/openjdk/6687968-pngimagereader_mem_leak.patch \
+	patches/openjdk/6541476-png-iTXt-chunk.patch \
+	patches/openjdk/6782079-png_metadata_oom.patch
 
 if WITH_ALT_HSBUILD
 ICEDTEA_PATCHES += \
diff -r f06befaad21b -r 7919aac747ab NEWS
--- a/NEWS	Thu Dec 23 15:52:22 2010 +0100
+++ b/NEWS	Tue Jan 04 08:55:53 2011 -0500
@@ -19,6 +19,9 @@ New in release 1.9.4 (2011-XX-XX):
   - S6976265: No STROKE_CONTROL
   - S6967434, PR450, RH530642: Round joins/caps of scaled up lines have poor quality.
   - S6438179, RH569121: XToolkit.isTraySupported() result has nothing to do with the system tray
+  - S6687968: PNGImageReader leaks native memory through an Inflater
+  - S6541476, RH665355: PNG imageio plugin incorrectly handles iTXt chunk
+  - S6782079: PNG: reading metadata may cause OOM on truncated images
 * Fixes
   - S7003777, RH647674: JTextPane produces incorrect content after parsing the html text
   - RH647157,RH582455: Update fontconfig files for rhel 6
diff -r f06befaad21b -r 7919aac747ab patches/openjdk/6541476-png-iTXt-chunk.patch
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/patches/openjdk/6541476-png-iTXt-chunk.patch	Tue Jan 04 08:55:53 2011 -0500
@@ -0,0 +1,549 @@
+diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java
+--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java	2010-12-23 17:11:16.193446425 -0500
++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageReader.java	2010-12-23 17:11:29.399447037 -0500
+@@ -44,7 +44,6 @@
+ import java.util.Arrays;
+ import java.util.Enumeration;
+ import java.util.Iterator;
+-import java.util.List;
+ import java.util.zip.Inflater;
+ import java.util.zip.InflaterInputStream;
+ import javax.imageio.IIOException;
+@@ -57,6 +56,7 @@
+ import com.sun.imageio.plugins.common.InputStreamAdapter;
+ import com.sun.imageio.plugins.common.ReaderUtil;
+ import com.sun.imageio.plugins.common.SubImageInputStream;
++import java.io.ByteArrayOutputStream;
+ import sun.awt.image.ByteInterleavedRaster;
+ 
+ class PNGImageDataEnumeration implements Enumeration {
+@@ -209,6 +209,15 @@
+         resetStreamSettings();
+     }
+ 
++    private String readNullTerminatedString(String charset) throws IOException {
++        ByteArrayOutputStream baos = new ByteArrayOutputStream();
++        int b;
++        while ((b = stream.read()) != 0) {
++            baos.write(b);
++        }
++        return new String(baos.toByteArray(), charset);
++    }
++
+     private String readNullTerminatedString() throws IOException {
+         StringBuilder b = new StringBuilder();
+         int c;
+@@ -447,26 +456,27 @@
+         metadata.iTXt_keyword.add(keyword);
+ 
+         int compressionFlag = stream.readUnsignedByte();
+-        metadata.iTXt_compressionFlag.add(new Integer(compressionFlag));
++        metadata.iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag == 1));
+ 
+         int compressionMethod = stream.readUnsignedByte();
+-        metadata.iTXt_compressionMethod.add(new Integer(compressionMethod));
++        metadata.iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
+ 
+-        String languageTag = readNullTerminatedString();
++        String languageTag = readNullTerminatedString("UTF8");
+         metadata.iTXt_languageTag.add(languageTag);
+ 
+-        String translatedKeyword = stream.readUTF();
++        String translatedKeyword =
++            readNullTerminatedString("UTF8");
+         metadata.iTXt_translatedKeyword.add(translatedKeyword);
+-        stream.skipBytes(1); // Null separator
+ 
+         String text;
++        long pos = stream.getStreamPosition();
++        byte[] b = new byte[(int)(chunkStart + chunkLength - pos)];
++        stream.readFully(b);
++
+         if (compressionFlag == 1) { // Decompress the text
+-            long pos = stream.getStreamPosition();
+-            byte[] b = new byte[(int)(chunkStart + chunkLength - pos)];
+-            stream.readFully(b);
+-            text = inflate(b);
++            text = new String(inflate(b), "UTF8");
+         } else {
+-            text = stream.readUTF();
++            text = new String(b, "UTF8");
+         }
+         metadata.iTXt_text.add(text);
+     }
+@@ -615,20 +625,20 @@
+         metadata.tRNS_present = true;
+     }
+ 
+-    private static String inflate(byte[] b) throws IOException {
++    private static byte[] inflate(byte[] b) throws IOException {
+         InputStream bais = new ByteArrayInputStream(b);
+         InputStream iis = new InflaterInputStream(bais);
++        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ 
+-        StringBuilder sb = new StringBuilder(80);
+         int c;
+         try {
+             while ((c = iis.read()) != -1) {
+-                sb.append((char)c);
++                baos.write(c);
+             }
+         } finally {
+             iis.close();
+         }
+-        return sb.toString();
++        return baos.toByteArray();
+     }
+ 
+     private void parse_zTXt_chunk(int chunkLength) throws IOException {
+@@ -640,7 +650,7 @@
+ 
+         byte[] b = new byte[chunkLength - keyword.length() - 2];
+         stream.readFully(b);
+-        metadata.zTXt_text.add(inflate(b));
++        metadata.zTXt_text.add(new String(inflate(b)));
+     }
+ 
+     private void readMetadata() throws IIOException {
+diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java
+--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java	2010-12-23 17:11:16.193446425 -0500
++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGImageWriter.java	2010-12-23 17:11:29.400446993 -0500
+@@ -671,13 +671,13 @@
+         }
+     }
+ 
+-    private byte[] deflate(String s) throws IOException {
++    private byte[] deflate(byte[] b) throws IOException {
+         ByteArrayOutputStream baos = new ByteArrayOutputStream();
+         DeflaterOutputStream dos = new DeflaterOutputStream(baos);
+ 
+-        int len = s.length();
++        int len = b.length;
+         for (int i = 0; i < len; i++) {
+-            dos.write((int)s.charAt(i));
++            dos.write((int)(0xff & b[i]));
+         }
+         dos.close();
+ 
+@@ -685,38 +685,37 @@
+     }
+ 
+     private void write_iTXt() throws IOException {
+-        Iterator keywordIter = metadata.iTXt_keyword.iterator();
+-        Iterator flagIter = metadata.iTXt_compressionFlag.iterator();
+-        Iterator methodIter = metadata.iTXt_compressionMethod.iterator();
+-        Iterator languageIter = metadata.iTXt_languageTag.iterator();
+-        Iterator translatedKeywordIter =
++        Iterator<String> keywordIter = metadata.iTXt_keyword.iterator();
++        Iterator<Boolean> flagIter = metadata.iTXt_compressionFlag.iterator();
++        Iterator<Integer> methodIter = metadata.iTXt_compressionMethod.iterator();
++        Iterator<String> languageIter = metadata.iTXt_languageTag.iterator();
++        Iterator<String> translatedKeywordIter =
+             metadata.iTXt_translatedKeyword.iterator();
+-        Iterator textIter = metadata.iTXt_text.iterator();
++        Iterator<String> textIter = metadata.iTXt_text.iterator();
+ 
+         while (keywordIter.hasNext()) {
+             ChunkStream cs = new ChunkStream(PNGImageReader.iTXt_TYPE, stream);
+-            String keyword = (String)keywordIter.next();
+-            cs.writeBytes(keyword);
++
++            cs.writeBytes(keywordIter.next());
+             cs.writeByte(0);
+ 
+-            int flag = ((Integer)flagIter.next()).intValue();
+-            cs.writeByte(flag);
+-            int method = ((Integer)methodIter.next()).intValue();
+-            cs.writeByte(method);
++            Boolean compressed = flagIter.next();
++            cs.writeByte(compressed ? 1 : 0);
+ 
+-            String languageTag = (String)languageIter.next();
+-            cs.writeBytes(languageTag);
++            cs.writeByte(methodIter.next().intValue());
++
++            cs.writeBytes(languageIter.next());
+             cs.writeByte(0);
+ 
+-            String translatedKeyword = (String)translatedKeywordIter.next();
+-            cs.writeBytes(translatedKeyword);
++
++            cs.write(translatedKeywordIter.next().getBytes("UTF8"));
+             cs.writeByte(0);
+ 
+-            String text = (String)textIter.next();
+-            if (flag == 1) {
+-                cs.write(deflate(text));
++            String text = textIter.next();
++            if (compressed) {
++                cs.write(deflate(text.getBytes("UTF8")));
+             } else {
+-                cs.writeUTF(text);
++                cs.write(text.getBytes("UTF8"));
+             }
+             cs.finish();
+         }
+@@ -737,7 +736,7 @@
+             cs.writeByte(compressionMethod);
+ 
+             String text = (String)textIter.next();
+-            cs.write(deflate(text));
++            cs.write(deflate(text.getBytes()));
+             cs.finish();
+         }
+     }
+diff -urN openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java
+--- openjdk.orig/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java	2010-06-21 17:15:11.000000000 -0400
++++ openjdk/jdk/src/share/classes/com/sun/imageio/plugins/png/PNGMetadata.java	2010-12-23 17:11:29.401446953 -0500
+@@ -176,12 +176,12 @@
+     public byte[] iCCP_compressedProfile;
+ 
+     // iTXt chunk
+-    public ArrayList iTXt_keyword = new ArrayList(); // Strings
+-    public ArrayList iTXt_compressionFlag = new ArrayList(); // Integers
+-    public ArrayList iTXt_compressionMethod = new ArrayList(); // Integers
+-    public ArrayList iTXt_languageTag = new ArrayList(); // Strings
+-    public ArrayList iTXt_translatedKeyword = new ArrayList(); // Strings
+-    public ArrayList iTXt_text = new ArrayList(); // Strings
++    public ArrayList<String> iTXt_keyword = new ArrayList<String>();
++    public ArrayList<Boolean> iTXt_compressionFlag = new ArrayList<Boolean>();
++    public ArrayList<Integer> iTXt_compressionMethod = new ArrayList<Integer>();
++    public ArrayList<String> iTXt_languageTag = new ArrayList<String>();
++    public ArrayList<String> iTXt_translatedKeyword = new ArrayList<String>();
++    public ArrayList<String> iTXt_text = new ArrayList<String>();
+ 
+     // pHYs chunk
+     public boolean pHYs_present;
+@@ -599,19 +599,17 @@
+         if (iTXt_keyword.size() > 0) {
+             IIOMetadataNode iTXt_parent = new IIOMetadataNode("iTXt");
+             for (int i = 0; i < iTXt_keyword.size(); i++) {
+-                Integer val;
+-
+                 IIOMetadataNode iTXt_node = new IIOMetadataNode("iTXtEntry");
+-                iTXt_node.setAttribute("keyword", (String)iTXt_keyword.get(i));
+-                val = (Integer)iTXt_compressionFlag.get(i);
+-                iTXt_node.setAttribute("compressionFlag", val.toString());
+-                val = (Integer)iTXt_compressionMethod.get(i);
+-                iTXt_node.setAttribute("compressionMethod", val.toString());
++                iTXt_node.setAttribute("keyword", iTXt_keyword.get(i));
++                iTXt_node.setAttribute("compressionFlag",
++                        iTXt_compressionFlag.get(i) ? "1" : "0");
++                iTXt_node.setAttribute("compressionMethod",
++                        iTXt_compressionMethod.get(i).toString());
+                 iTXt_node.setAttribute("languageTag",
+-                                       (String)iTXt_languageTag.get(i));
++                                       iTXt_languageTag.get(i));
+                 iTXt_node.setAttribute("translatedKeyword",
+-                                       (String)iTXt_translatedKeyword.get(i));
+-                iTXt_node.setAttribute("text", (String)iTXt_text.get(i));
++                                       iTXt_translatedKeyword.get(i));
++                iTXt_node.setAttribute("text", iTXt_text.get(i));
+ 
+                 iTXt_parent.appendChild(iTXt_node);
+             }
+@@ -1039,11 +1037,11 @@
+ 
+         for (int i = 0; i < iTXt_keyword.size(); i++) {
+             node = new IIOMetadataNode("TextEntry");
+-            node.setAttribute("keyword", (String)iTXt_keyword.get(i));
+-            node.setAttribute("value", (String)iTXt_text.get(i));
++            node.setAttribute("keyword", iTXt_keyword.get(i));
++            node.setAttribute("value", iTXt_text.get(i));
+             node.setAttribute("language",
+-                              (String)iTXt_languageTag.get(i));
+-            if (((Integer)iTXt_compressionFlag.get(i)).intValue() == 1) {
++                              iTXt_languageTag.get(i));
++            if (iTXt_compressionFlag.get(i)) {
+                 node.setAttribute("compression", "deflate");
+             } else {
+                 node.setAttribute("compression", "none");
+@@ -1429,11 +1427,11 @@
+ 
+                     boolean compressionFlag =
+                         getBooleanAttribute(iTXt_node, "compressionFlag");
+-                    iTXt_compressionFlag.add(new Boolean(compressionFlag));
++                    iTXt_compressionFlag.add(Boolean.valueOf(compressionFlag));
+ 
+                     String compressionMethod =
+                         getAttribute(iTXt_node, "compressionMethod");
+-                    iTXt_compressionMethod.add(compressionMethod);
++                    iTXt_compressionMethod.add(Integer.valueOf(compressionMethod));
+ 
+                     String languageTag =
+                         getAttribute(iTXt_node, "languageTag");
+@@ -1952,13 +1950,10 @@
+                                 tEXt_text.add(value);
+                             }
+                         } else {
+-                            int flag = compression.equals("zip") ?
+-                                1 : 0;
+-
+                             // Use an iTXt node
+                             iTXt_keyword.add(keyword);
+-                            iTXt_compressionFlag.add(new Integer(flag));
+-                            iTXt_compressionMethod.add(new Integer(0));
++                            iTXt_compressionFlag.add(Boolean.valueOf(compression.equals("zip")));
++                            iTXt_compressionMethod.add(Integer.valueOf(0));
+                             iTXt_languageTag.add(language);
+                             iTXt_translatedKeyword.add(keyword); // fake it
+                             iTXt_text.add(value);
+@@ -1995,12 +1990,12 @@
+         gAMA_present = false;
+         hIST_present = false;
+         iCCP_present = false;
+-        iTXt_keyword = new ArrayList();
+-        iTXt_compressionFlag = new ArrayList();
+-        iTXt_compressionMethod = new ArrayList();
+-        iTXt_languageTag = new ArrayList();
+-        iTXt_translatedKeyword = new ArrayList();
+-        iTXt_text = new ArrayList();
++        iTXt_keyword = new ArrayList<String>();
++        iTXt_compressionFlag = new ArrayList<Boolean>();
++        iTXt_compressionMethod = new ArrayList<Integer>();
++        iTXt_languageTag = new ArrayList<String>();
++        iTXt_translatedKeyword = new ArrayList<String>();
++        iTXt_text = new ArrayList<String>();
+         pHYs_present = false;
+         sBIT_present = false;
+         sPLT_present = false;
+diff -urN openjdk.orig/jdk/test/javax/imageio/plugins/png/ITXtTest.java openjdk/jdk/test/javax/imageio/plugins/png/ITXtTest.java
+--- openjdk.orig/jdk/test/javax/imageio/plugins/png/ITXtTest.java	1969-12-31 19:00:00.000000000 -0500
++++ openjdk/jdk/test/javax/imageio/plugins/png/ITXtTest.java	2010-12-23 17:12:58.538446639 -0500
+@@ -0,0 +1,236 @@
++/*
++ * Copyright (c) 2008, Oracle and/or its affiliates. All rights reserved.
++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
++ *
++ * This code is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 only, as
++ * published by the Free Software Foundation.
++ *
++ * This code is distributed in the hope that it will be useful, but WITHOUT
++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
++ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
++ * version 2 for more details (a copy is included in the LICENSE file that
++ * accompanied this code).
++ *
++ * You should have received a copy of the GNU General Public License version
++ * 2 along with this work; if not, write to the Free Software Foundation,
++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
++ *
++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
++ * or visit www.oracle.com if you need additional information or have any
++ * questions.
++ */
++
++/**
++ * @test
++ * @bug     6541476
++ * @summary Test verifies that ImageIO PNG plugin correcly handles the
++ *          iTxt chunk (International textual data).
++ *
++ * @run     main ITXtTest
++ */
++
++
++import java.awt.Color;
++import java.awt.Graphics2D;
++import java.awt.image.BufferedImage;
++import java.io.File;
++
++import javax.imageio.ImageIO;
++import javax.imageio.ImageReader;
++import javax.imageio.IIOImage;
++import javax.imageio.ImageTypeSpecifier;
++import javax.imageio.ImageWriter;
++import javax.imageio.metadata.IIOMetadata;
++import javax.imageio.metadata.IIOMetadataNode;
++import javax.imageio.stream.ImageOutputStream;
++import javax.imageio.stream.ImageInputStream;
++
++import org.w3c.dom.Node;
++
++public class ITXtTest {
++    static public void main(String args[]) {
++        ITXtTest t_en = new ITXtTest();
++        t_en.description = "xml - en";
++        t_en.keyword = "XML:com.adobe.xmp";
++        t_en.isCompressed = false;
++        t_en.compression = 0;
++        t_en.language = "en";
++        t_en.trasKeyword = "XML:com.adobe.xmp";
++        t_en.text = "<xml>Something</xml>";
++
++        doTest(t_en);
++
++        // check compression case
++        t_en.isCompressed = true;
++        t_en.description = "xml - en - compressed";
++
++        doTest(t_en);
++
++        ITXtTest t_ru = new ITXtTest();
++        t_ru.description = "xml - ru";
++        t_ru.keyword = "XML:com.adobe.xmp";
++        t_ru.isCompressed = false;
++        t_ru.compression = 0;
++        t_ru.language = "ru";
++        t_ru.trasKeyword = "\u0410\u0410\u0410\u0410\u0410 XML";
++        t_ru.text = "<xml>\u042A\u042F\u042F\u042F\u042F\u042F\u042F</xml>";
++
++        doTest(t_ru);
++
++        t_ru.isCompressed = true;
++        t_ru.description = "xml - ru - compressed";
++
++        doTest(t_ru);
++    }
++
++
++    String description;
++
++    String keyword;
++    boolean isCompressed;
++    int compression;
++    String language;
++    String trasKeyword;
++    String text;
++
++
++    public IIOMetadataNode getNode() {
++        IIOMetadataNode iTXt = new IIOMetadataNode("iTXt");
++        IIOMetadataNode iTXtEntry = new IIOMetadataNode("iTXtEntry");
++        iTXtEntry.setAttribute("keyword", keyword);
++        iTXtEntry.setAttribute("compressionFlag",
++                               isCompressed ? "true" : "false");
++        iTXtEntry.setAttribute("compressionMethod",
++                               Integer.toString(compression));
++        iTXtEntry.setAttribute("languageTag", language);
++        iTXtEntry.setAttribute("translatedKeyword",
++                               trasKeyword);
++        iTXtEntry.setAttribute("text", text);
++        iTXt.appendChild(iTXtEntry);
++        return iTXt;
++    }
++
++    public static ITXtTest getFromNode(IIOMetadataNode n) {
++        ITXtTest t = new ITXtTest();
++
++        if (!"iTXt".equals(n.getNodeName())) {
++            throw new RuntimeException("Invalid node");
++        }
++        IIOMetadataNode e = (IIOMetadataNode)n.getFirstChild();
++        if (!"iTXtEntry".equals(e.getNodeName())) {
++            throw new RuntimeException("Invalid entry node");
++        }
++        t.keyword = e.getAttribute("keyword");
++        t.isCompressed =
++            (Integer.valueOf(e.getAttribute("compressionFlag")).intValue() == 1);
++        t.compression =
++            Integer.valueOf(e.getAttribute("compressionMethod")).intValue();
++        t.language = e.getAttribute("languageTag");
++        t.trasKeyword = e.getAttribute("translatedKeyword");
++        t.text = e.getAttribute("text");
++
++        return t;



More information about the distro-pkg-dev mailing list