diff options
73 files changed, 977 insertions, 2435 deletions
@@ -210,8 +210,8 @@ maven_jar( maven_jar( name = "mockito", - artifact = "org.mockito:mockito-core:5.14.1", - sha1 = "a89b0ce9ee5d92646522caeb27fb92c02a0b4c55", + artifact = "org.mockito:mockito-core:5.14.2", + sha1 = "f7bf936008d7664e2002c3faf0c02071c8d10e7c", ) maven_jar( @@ -220,18 +220,18 @@ maven_jar( sha1 = "0d26263eb7524252d98e602fc6942996a3195e29", ) -BYTE_BUDDY_VERSION = "1.15.3" +BYTE_BUDDY_VERSION = "1.15.10" maven_jar( name = "bytebuddy", artifact = "net.bytebuddy:byte-buddy:" + BYTE_BUDDY_VERSION, - sha1 = "01b3069696cd9ed55d90b9114ffe3429035ff924", + sha1 = "635c873fadd853c084f84fdc3cbd58c5dd8537f9", ) maven_jar( name = "bytebuddy-agent", artifact = "net.bytebuddy:byte-buddy-agent:" + BYTE_BUDDY_VERSION, - sha1 = "e619d89ed41a6cedc23bee3549cec8c4ffdaee7b", + sha1 = "0e8eb255b2c378b9a6c7341e7b0e12f0a5636377", ) maven_jar( @@ -296,32 +296,32 @@ maven_jar( sha1 = "6f4beb9b482ea0d9db9db0564742aa2e4e0bf3c4", ) -BOUNCYCASTLE_VER = "1.78.1" +BOUNCYCASTLE_VER = "1.79" maven_jar( name = "bcpg", artifact = "org.bouncycastle:bcpg-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "6c8dbcec20355278ec54840e735f63db2479150e", - src_sha1 = "2ddef60d84dd8c14ebce4c13100f0bc55fed6922", + sha1 = "904dd8a8e1c9f7d58d1ffa7f4ca3fb00736a601f", + src_sha1 = "9e372826141edb213d5921131ee68dc276dc99ef", ) maven_jar( name = "bcprov", artifact = "org.bouncycastle:bcprov-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "39e9e45359e20998eb79c1828751f94a818d25f8", - src_sha1 = "70f58ec93da543dda6a21614b768cb2e386fd512", + sha1 = "4d8e2732bcee15f1db93df266c3f5b70ce5cac21", + src_sha1 = "8647816d667ee526a8e3a456229ac5f9f96d2315", ) maven_jar( name = "bcutil", artifact = "org.bouncycastle:bcutil-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "5353ca39fe2f148dab9ca1d637a43d0750456254", - src_sha1 = "8d2e0747f5d806f39a602f7f91610444d88c4e2c", + sha1 = "ecfc5aef97cc7676ea0de5c53c407b9f533f0ad5", + src_sha1 = "00df03977fb0b80395da655623abca9d7d7dcb66", ) maven_jar( name = "bcpkix", artifact = "org.bouncycastle:bcpkix-jdk18on:" + BOUNCYCASTLE_VER, - sha1 = "17b3541f736df97465f87d9f5b5dfa4991b37bb3", - src_sha1 = "3aeaf221772ad0c9c04593688cb86c6eb74d48b9", + sha1 = "7693cec3b8779b74b35466dcaeeaac7409872954", + src_sha1 = "57a60d1d9f75320eef70a095dfae679d97ade1c2", ) diff --git a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF index c71f9b6541..a86f5ab2c6 100644 --- a/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc.test/META-INF/MANIFEST.MF @@ -8,11 +8,12 @@ Bundle-Vendor: %Bundle-Vendor Bundle-Localization: plugin Bundle-RequiredExecutionEnvironment: JavaSE-17 Require-Bundle: org.hamcrest.core;bundle-version="[1.3.0,2.0.0)" -Import-Package: org.bouncycastle.jce.provider;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp.operator;version="[1.65.0,2.0.0)", - org.bouncycastle.openpgp.operator.jcajce;version="[1.65.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.65.0,2.0.0)", +Import-Package: org.bouncycastle.asn1.cryptlib;version="[1.79.0,2.0.0)", + org.bouncycastle.jce.provider;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)", org.eclipse.jgit.gpg.bc.internal;version="[7.1.0,7.2.0)", org.eclipse.jgit.gpg.bc.internal.keys;version="[7.1.0,7.2.0)", org.eclipse.jgit.util.sha1;version="[7.1.0,7.2.0)", diff --git a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java index fed06103b6..d486c977f0 100644 --- a/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java +++ b/org.eclipse.jgit.gpg.bc.test/tst/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeysTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.org> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -9,10 +9,7 @@ */ package org.eclipse.jgit.gpg.bc.internal.keys; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.IOException; @@ -20,8 +17,6 @@ import java.io.InputStream; import java.security.Security; import java.util.Iterator; -import javax.crypto.Cipher; - import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; @@ -49,39 +44,15 @@ public class SecretKeysTest { } } - private static volatile Boolean haveOCB; - - private static boolean ocbAvailable() { - Boolean haveIt = haveOCB; - if (haveIt != null) { - return haveIt.booleanValue(); - } - try { - Cipher c = Cipher.getInstance("AES/OCB/NoPadding"); //$NON-NLS-1$ - if (c == null) { - haveOCB = Boolean.FALSE; - return false; - } - } catch (NoClassDefFoundError | Exception e) { - haveOCB = Boolean.FALSE; - return false; - } - haveOCB = Boolean.TRUE; - return true; - } - private static class TestData { final String name; final boolean encrypted; - final boolean keyValue; - - TestData(String name, boolean encrypted, boolean keyValue) { + TestData(String name, boolean encrypted) { this.name = name; this.encrypted = encrypted; - this.keyValue = keyValue; } @Override @@ -93,19 +64,12 @@ public class SecretKeysTest { @Parameters(name = "{0}") public static TestData[] initTestData() { return new TestData[] { - new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false, false), - new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false, true), - new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true, true), - new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true, true), - new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true, true), - new TestData("faked", false, true) }; - } - - private static byte[] readTestKey(String filename) throws Exception { - try (InputStream in = new BufferedInputStream( - SecretKeysTest.class.getResourceAsStream(filename))) { - return SecretKeys.keyFromNameValueFormat(in); - } + new TestData("AFDA8EA10E185ACF8C0D0F8885A0EF61A72ECB11", false), + new TestData("2FB05DBB70FC07CB84C13431F640CA6CEA1DBF8A", false), + new TestData("66CCECEC2AB46A9735B10FEC54EDF9FD0F77BAF9", true), + new TestData("F727FAB884DA3BD402B6E0F5472E108D21033124", true), + new TestData("62D43D7F117F7A5E4998ECB6617EE9942D069C14", true), + new TestData("faked", false) }; } private static PGPPublicKey readAsc(InputStream in) @@ -131,11 +95,6 @@ public class SecretKeysTest { @Test public void testKeyRead() throws Exception { - if (data.keyValue) { - byte[] bytes = readTestKey(data.name + ".key"); - assertEquals('(', bytes[0]); - assertEquals(')', bytes[bytes.length - 1]); - } try (InputStream pubIn = this.getClass() .getResourceAsStream(data.name + ".asc")) { if (pubIn != null) { @@ -151,11 +110,6 @@ public class SecretKeysTest { : null, publicKey); assertNotNull(secretKey); - } catch (PGPException e) { - // Currently we may not be able to load OCB-encrypted keys. - assertTrue(e.toString(), e.getMessage().contains("OCB")); - assertTrue(data.encrypted); - assertFalse(ocbAvailable()); } } } diff --git a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF index 6e3321ebf6..1413c44dcb 100644 --- a/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.gpg.bc/META-INF/MANIFEST.MF @@ -8,26 +8,23 @@ Bundle-Vendor: %Bundle-Vendor Bundle-Localization: OSGI-INF/l10n/gpg_bc Bundle-Version: 7.1.0.qualifier Bundle-RequiredExecutionEnvironment: JavaSE-17 -Import-Package: org.bouncycastle.asn1;version="[1.69.0,2.0.0)", - org.bouncycastle.asn1.x9;version="[1.69.0,2.0.0)", - org.bouncycastle.bcpg;version="[1.69.0,2.0.0)", - org.bouncycastle.bcpg.sig;version="[1.69.0,2.0.0)", - org.bouncycastle.crypto.ec;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg.keybox;version="[1.69.0,2.0.0)", - org.bouncycastle.gpg.keybox.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.jcajce.interfaces;version="[1.69.0,2.0.0)", - org.bouncycastle.jcajce.util;version="[1.69.0,2.0.0)", - org.bouncycastle.jce.provider;version="[1.69.0,2.0.0)", - org.bouncycastle.math.ec;version="[1.69.0,2.0.0)", - org.bouncycastle.math.field;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.operator;version="[1.69.0,2.0.0)", - org.bouncycastle.openpgp.operator.jcajce;version="[1.69.0,2.0.0)", - org.bouncycastle.util;version="[1.69.0,2.0.0)", - org.bouncycastle.util.encoders;version="[1.69.0,2.0.0)", - org.bouncycastle.util.io;version="[1.69.0,2.0.0)", +Import-Package: org.bouncycastle.asn1;version="[1.79.0,2.0.0)", + org.bouncycastle.asn1.x9;version="[1.79.0,2.0.0)", + org.bouncycastle.bcpg;version="[1.79.0,2.0.0)", + org.bouncycastle.bcpg.sig;version="[1.79.0,2.0.0)", + org.bouncycastle.crypto.ec;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg.keybox;version="[1.79.0,2.0.0)", + org.bouncycastle.gpg.keybox.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.jcajce.interfaces;version="[1.79.0,2.0.0)", + org.bouncycastle.jcajce.util;version="[1.79.0,2.0.0)", + org.bouncycastle.math.ec;version="[1.79.0,2.0.0)", + org.bouncycastle.math.field;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator;version="[1.79.0,2.0.0)", + org.bouncycastle.openpgp.operator.jcajce;version="[1.79.0,2.0.0)", + org.bouncycastle.util.encoders;version="[1.79.0,2.0.0)", org.slf4j;version="[1.7.0,3.0.0)" Export-Package: org.eclipse.jgit.gpg.bc.internal;version="7.1.0";x-friends:="org.eclipse.jgit.gpg.bc.test", org.eclipse.jgit.gpg.bc.internal.keys;version="7.1.0";x-friends:="org.eclipse.jgit.gpg.bc.test" diff --git a/org.eclipse.jgit.gpg.bc/about.html b/org.eclipse.jgit.gpg.bc/about.html index fc527d5a3a..92b9409831 100644 --- a/org.eclipse.jgit.gpg.bc/about.html +++ b/org.eclipse.jgit.gpg.bc/about.html @@ -58,32 +58,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWIS ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</p> -<hr> -<p><b>org.eclipse.jgit.gpg.bc.internal.keys.SExprParser - MIT</b></p> - -<p>Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. -(<a href="https://www.bouncycastle.org">https://www.bouncycastle.org</a>)</p> - -<p> -Permission is hereby granted, free of charge, to any person obtaining a copy of this software -and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: -</p> -<p> -The above copyright notice and this permission notice shall be included in all copies or substantial -portions of the Software. -</p> -<p> -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. -</p> - </body> </html> diff --git a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties index 77ca2cd0a4..9e7f98cab1 100644 --- a/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties +++ b/org.eclipse.jgit.gpg.bc/resources/org/eclipse/jgit/gpg/bc/internal/BCText.properties @@ -1,7 +1,5 @@ corrupt25519Key=Ed25519/Curve25519 public key has wrong length: {0} credentialPassphrase=Passphrase -cryptCipherError=Cannot create cipher to decrypt: {0} -cryptWrongDecryptedLength=Decrypted key has wrong length; expected {0} bytes, got only {1} bytes gpgFailedToParseSecretKey=Failed to parse secret key file {0}. Is the entered passphrase correct? gpgNoCredentialsProvider=missing credentials provider gpgNoKeygrip=Cannot find key {0}: cannot determine key grip @@ -9,22 +7,14 @@ gpgNoKeyring=neither pubring.kbx nor secring.gpg files found gpgNoKeyInLegacySecring=no matching secret key found in legacy secring.gpg for key or user id: {0} gpgNoPublicKeyFound=Unable to find a public-key with key or user id: {0} gpgNoSecretKeyForPublicKey=unable to find associated secret key for public key: {0} -gpgNoSuchAlgorithm=Cannot decrypt encrypted secret key: encryption algorithm {0} is not available gpgNotASigningKey=Secret key ({0}) is not suitable for signing gpgKeyInfo=GPG Key (fingerprint {0}) gpgSigningCancelled=Signing was cancelled +keyAlgorithmMismatch=Secret key has a different algorithm than the public key +keyMismatch=Secret key does not match public key; public key is {0} {1} while secret key is for {2} {3} logWarnGnuPGHome=Cannot access GPG home directory given by environment variable GNUPGHOME={} logWarnGpgHomeProperty=Cannot access GPG home directory given by Java system property jgit.gpg.home={} nonSignatureError=Signature does not decode into a signature object -secretKeyTooShort=Secret key file corrupt; only {0} bytes read -sexprHexNotClosed=Hex number in s-expression not closed -sexprHexOdd=Hex number in s-expression has an odd number of digits -sexprStringInvalidEscape=Invalid escape {0} in s-expression -sexprStringInvalidEscapeAtEnd=Invalid s-expression: quoted string ends with escape character -sexprStringInvalidHexEscape=Invalid hex escape in s-expression -sexprStringInvalidOctalEscape=Invalid octal escape in s-expression -sexprStringNotClosed=String in s-expression not closed -sexprUnhandled=Unhandled token {0} in s-expression signatureInconsistent=Inconsistent signature; key ID {0} does not match issuer fingerprint {1} signatureKeyLookupError=Error occurred while looking for public key signatureNoKeyInfo=No way to determine a public key from the signature diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java index 705e195e44..fcae7c2b98 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BCText.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018, 2021 Salesforce and others + * Copyright (C) 2018, 2024 Salesforce and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -30,8 +30,6 @@ public final class BCText extends TranslationBundle { // @formatter:off /***/ public String corrupt25519Key; /***/ public String credentialPassphrase; - /***/ public String cryptCipherError; - /***/ public String cryptWrongDecryptedLength; /***/ public String gpgFailedToParseSecretKey; /***/ public String gpgNoCredentialsProvider; /***/ public String gpgNoKeygrip; @@ -39,22 +37,14 @@ public final class BCText extends TranslationBundle { /***/ public String gpgNoKeyInLegacySecring; /***/ public String gpgNoPublicKeyFound; /***/ public String gpgNoSecretKeyForPublicKey; - /***/ public String gpgNoSuchAlgorithm; /***/ public String gpgNotASigningKey; /***/ public String gpgKeyInfo; /***/ public String gpgSigningCancelled; + /***/ public String keyAlgorithmMismatch; + /***/ public String keyMismatch; /***/ public String logWarnGnuPGHome; /***/ public String logWarnGpgHomeProperty; /***/ public String nonSignatureError; - /***/ public String secretKeyTooShort; - /***/ public String sexprHexNotClosed; - /***/ public String sexprHexOdd; - /***/ public String sexprStringInvalidEscape; - /***/ public String sexprStringInvalidEscapeAtEnd; - /***/ public String sexprStringInvalidHexEscape; - /***/ public String sexprStringInvalidOctalEscape; - /***/ public String sexprStringNotClosed; - /***/ public String sexprUnhandled; /***/ public String signatureInconsistent; /***/ public String signatureKeyLookupError; /***/ public String signatureNoKeyInfo; diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java index 1d187a5db2..adac9b199d 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/BouncyCastleGpgSigner.java @@ -105,7 +105,8 @@ public class BouncyCastleGpgSigner implements Signer { PGPSignatureGenerator signatureGenerator = new PGPSignatureGenerator( new JcaPGPContentSignerBuilder( publicKey.getAlgorithm(), - HashAlgorithmTags.SHA256)); + HashAlgorithmTags.SHA256), + publicKey); signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, privateKey); PGPSignatureSubpacketGenerator subpackets = new PGPSignatureSubpacketGenerator(); subpackets.setIssuerFingerprint(false, publicKey); diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java deleted file mode 100644 index 3924d68596..0000000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/OCBPBEProtectionRemoverFactory.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -import java.security.NoSuchAlgorithmException; -import java.text.MessageFormat; - -import javax.crypto.Cipher; -import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPUtil; -import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.util.Arrays; -import org.eclipse.jgit.gpg.bc.internal.BCText; - -/** - * A {@link PBEProtectionRemoverFactory} using AES/OCB/NoPadding for decryption. - * It accepts an AAD in the factory's constructor, so the factory can be used to - * create a {@link PBESecretKeyDecryptor} only for a particular input. - * <p> - * For JGit's needs, this is sufficient, but for a general upstream - * implementation that limitation might not be acceptable. - * </p> - */ -class OCBPBEProtectionRemoverFactory - implements PBEProtectionRemoverFactory { - - private final PGPDigestCalculatorProvider calculatorProvider; - - private final char[] passphrase; - - private final byte[] aad; - - /** - * Creates a new factory instance with the given parameters. - * <p> - * Because the AAD is given at factory level, the {@link PBESecretKeyDecryptor}s - * created by the factory can be used to decrypt only a particular input - * matching this AAD. - * </p> - * - * @param passphrase to use for secret key derivation - * @param calculatorProvider for computing digests - * @param aad for the OCB decryption - */ - OCBPBEProtectionRemoverFactory(char[] passphrase, - PGPDigestCalculatorProvider calculatorProvider, byte[] aad) { - this.calculatorProvider = calculatorProvider; - this.passphrase = passphrase; - this.aad = aad; - } - - @Override - public PBESecretKeyDecryptor createDecryptor(String protection) - throws PGPException { - return new PBESecretKeyDecryptor(passphrase, calculatorProvider) { - - @Override - public byte[] recoverKeyData(int encAlgorithm, byte[] key, - byte[] iv, byte[] encrypted, int encryptedOffset, - int encryptedLength) throws PGPException { - String algorithmName = PGPUtil - .getSymmetricCipherName(encAlgorithm); - byte[] decrypted = null; - try { - // errorprone: "Dynamically constructed transformation - // strings are also flagged, as they may conceal an instance - // of ECB mode." - @SuppressWarnings("InsecureCryptoUsage") - Cipher c = Cipher - .getInstance(algorithmName + "/OCB/NoPadding"); //$NON-NLS-1$ - SecretKey secretKey = new SecretKeySpec(key, algorithmName); - c.init(Cipher.DECRYPT_MODE, secretKey, - new IvParameterSpec(iv)); - c.updateAAD(aad); - decrypted = new byte[c.getOutputSize(encryptedLength)]; - int decryptedLength = c.update(encrypted, encryptedOffset, - encryptedLength, decrypted); - // doFinal() for OCB will check the MAC and throw an - // exception if it doesn't match - decryptedLength += c.doFinal(decrypted, decryptedLength); - if (decryptedLength != decrypted.length) { - throw new PGPException(MessageFormat.format( - BCText.get().cryptWrongDecryptedLength, - Integer.valueOf(decryptedLength), - Integer.valueOf(decrypted.length))); - } - byte[] result = decrypted; - decrypted = null; // Don't clear in finally - return result; - } catch (NoClassDefFoundError e) { - String msg = MessageFormat.format( - BCText.get().gpgNoSuchAlgorithm, - algorithmName + "/OCB"); //$NON-NLS-1$ - throw new PGPException(msg, - new NoSuchAlgorithmException(msg, e)); - } catch (PGPException e) { - throw e; - } catch (Exception e) { - throw new PGPException( - MessageFormat.format(BCText.get().cryptCipherError, - e.getLocalizedMessage()), - e); - } finally { - if (decrypted != null) { - // Prevent halfway decrypted data leaking. - Arrays.fill(decrypted, (byte) 0); - } - } - } - }; - } -}
\ No newline at end of file diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java deleted file mode 100644 index fd030ee032..0000000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SExprParser.java +++ /dev/null @@ -1,859 +0,0 @@ -/* - * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) - * <p> - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * </p> - * <p> - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. - * </p> - * <p> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * </p> - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; -import java.util.Date; - -import org.bouncycastle.asn1.ASN1ObjectIdentifier; -import org.bouncycastle.asn1.x9.ECNamedCurveTable; -import org.bouncycastle.bcpg.DSAPublicBCPGKey; -import org.bouncycastle.bcpg.DSASecretBCPGKey; -import org.bouncycastle.bcpg.ECDSAPublicBCPGKey; -import org.bouncycastle.bcpg.ECPublicBCPGKey; -import org.bouncycastle.bcpg.ECSecretBCPGKey; -import org.bouncycastle.bcpg.ElGamalPublicBCPGKey; -import org.bouncycastle.bcpg.ElGamalSecretBCPGKey; -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; -import org.bouncycastle.bcpg.PublicKeyPacket; -import org.bouncycastle.bcpg.RSAPublicBCPGKey; -import org.bouncycastle.bcpg.RSASecretBCPGKey; -import org.bouncycastle.bcpg.S2K; -import org.bouncycastle.bcpg.SecretKeyPacket; -import org.bouncycastle.bcpg.SymmetricKeyAlgorithmTags; -import org.bouncycastle.openpgp.PGPException; -import org.bouncycastle.openpgp.PGPPublicKey; -import org.bouncycastle.openpgp.PGPSecretKey; -import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; -import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; -import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; -import org.bouncycastle.openpgp.operator.PGPDigestCalculator; -import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; -import org.bouncycastle.util.Arrays; -import org.bouncycastle.util.Strings; - -/** - * A parser for secret keys stored in s-expressions. Original BouncyCastle code - * modified by the JGit team to: - * <ul> - * <li>handle unencrypted DSA, EC, and ElGamal keys (upstream only handles - * unencrypted RSA)</li> - * <li>handle secret keys using AES/OCB as encryption (those don't have a - * hash)</li> - * <li>fix EC parsing to account for "flags" sub-list present for ed25519 and - * curve25519</li> - * <li>add support for ed25519 OIDs unknown to BouncyCastle</li> - * </ul> - */ -@SuppressWarnings("nls") -public class SExprParser { - private final PGPDigestCalculatorProvider digestProvider; - - /** - * Base constructor. - * - * @param digestProvider - * a provider for digest calculations. Used to confirm key - * protection hashes. - */ - public SExprParser(PGPDigestCalculatorProvider digestProvider) { - this.digestProvider = digestProvider; - } - - /** - * Parse a secret key from one of the GPG S expression keys associating it - * with the passed in public key. - * - * @param inputStream - * to read from - * @param keyProtectionRemoverFactory - * for decrypting encrypted keys - * @param pubKey - * the private key should belong to - * - * @return a secret key object. - * @throws IOException - * if an IO error occurred - * @throws PGPException - * if some PGP error occurred - */ - public PGPSecretKey parseSecretKey(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory, - PGPPublicKey pubKey) throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type; - - type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected-private-key") - || type.equals("private-key")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String keyType = SXprUtils.readString(inputStream, - inputStream.read()); - if (keyType.equals("ecc")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String curveID = SXprUtils.readString(inputStream, - inputStream.read()); - String curveName = SXprUtils.readString(inputStream, - inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] qVal; - - SXprUtils.skipOpenParenthesis(inputStream); - - type = SXprUtils.readString(inputStream, inputStream.read()); - // JGit: c.f. https://github.com/bcgit/bc-java/issues/1590. - // There may be a flags sub-list here for ed25519 or curve25519. - if (type.equals("flags")) { - SXprUtils.readString(inputStream, inputStream.read()); - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipOpenParenthesis(inputStream); - type = SXprUtils.readString(inputStream, - inputStream.read()); - } - if (type.equals("q")) { - qVal = SXprUtils.readBytes(inputStream, inputStream.read()); - } else { - throw new PGPException("no q value found"); - } - - SXprUtils.skipCloseParenthesis(inputStream); - - BigInteger d = processECSecretKey(inputStream, curveID, - curveName, qVal, keyProtectionRemoverFactory); - - if (curveName.startsWith("NIST ")) { - curveName = curveName.substring("NIST ".length()); - } - - // JGit: BC doesn't know Ed25519 curve name. - ASN1ObjectIdentifier curveOid = ECNamedCurveTable - .getOID(curveName); - if (curveOid == null) { - curveOid = ObjectIds.getByName(curveName); - } - ECPublicBCPGKey basePubKey = new ECDSAPublicBCPGKey( - curveOid, - new BigInteger(1, qVal)); - ECPublicBCPGKey assocPubKey = (ECPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!ObjectIds.match(basePubKey.getCurveOID(), - assocPubKey.getCurveOID()) - || !basePubKey.getEncodedPoint() - .equals(assocPubKey.getEncodedPoint())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new ECSecretBCPGKey(d).getEncoded()), - pubKey); - } else if (keyType.equals("dsa")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger q = readBigInteger("q", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processDSASecretKey(inputStream, p, q, g, y, - keyProtectionRemoverFactory); - - DSAPublicBCPGKey basePubKey = new DSAPublicBCPGKey(p, q, g, y); - DSAPublicBCPGKey assocPubKey = (DSAPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getP().equals(assocPubKey.getP()) - || !basePubKey.getQ().equals(assocPubKey.getQ()) - || !basePubKey.getG().equals(assocPubKey.getG()) - || !basePubKey.getY().equals(assocPubKey.getY())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new DSASecretBCPGKey(x).getEncoded()), - pubKey); - } else if (keyType.equals("elg")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processElGamalSecretKey(inputStream, p, g, y, - keyProtectionRemoverFactory); - - ElGamalPublicBCPGKey basePubKey = new ElGamalPublicBCPGKey(p, g, - y); - ElGamalPublicBCPGKey assocPubKey = (ElGamalPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getP().equals(assocPubKey.getP()) - || !basePubKey.getG().equals(assocPubKey.getG()) - || !basePubKey.getY().equals(assocPubKey.getY())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey( - new SecretKeyPacket(pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new ElGamalSecretBCPGKey(x).getEncoded()), - pubKey); - } else if (keyType.equals("rsa")) { - BigInteger n = readBigInteger("n", inputStream); - BigInteger e = readBigInteger("e", inputStream); - - BigInteger[] values = processRSASecretKey(inputStream, n, e, - keyProtectionRemoverFactory); - - // TODO: type of RSA key? - RSAPublicBCPGKey basePubKey = new RSAPublicBCPGKey(n, e); - RSAPublicBCPGKey assocPubKey = (RSAPublicBCPGKey) pubKey - .getPublicKeyPacket().getKey(); - if (!basePubKey.getModulus().equals(assocPubKey.getModulus()) - || !basePubKey.getPublicExponent() - .equals(assocPubKey.getPublicExponent())) { - throw new PGPException( - "passed in public key does not match secret key"); - } - - return new PGPSecretKey(new SecretKeyPacket( - pubKey.getPublicKeyPacket(), - SymmetricKeyAlgorithmTags.NULL, null, null, - new RSASecretBCPGKey(values[0], values[1], values[2]) - .getEncoded()), - pubKey); - } else { - throw new PGPException("unknown key type: " + keyType); - } - } - - throw new PGPException("unknown key type found"); - } - - /** - * Parse a secret key from one of the GPG S expression keys. - * - * @param inputStream - * to read from - * @param keyProtectionRemoverFactory - * for decrypting encrypted keys - * @param fingerPrintCalculator - * for calculating key fingerprints - * - * @return a secret key object. - * @throws IOException - * if an IO error occurred - * @throws PGPException - * if a PGP error occurred - */ - public PGPSecretKey parseSecretKey(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory, - KeyFingerPrintCalculator fingerPrintCalculator) - throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type; - - type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected-private-key") - || type.equals("private-key")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String keyType = SXprUtils.readString(inputStream, - inputStream.read()); - if (keyType.equals("ecc")) { - SXprUtils.skipOpenParenthesis(inputStream); - - String curveID = SXprUtils.readString(inputStream, - inputStream.read()); - String curveName = SXprUtils.readString(inputStream, - inputStream.read()); - - if (curveName.startsWith("NIST ")) { - curveName = curveName.substring("NIST ".length()); - } - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] qVal; - - SXprUtils.skipOpenParenthesis(inputStream); - - type = SXprUtils.readString(inputStream, inputStream.read()); - // JGit: c.f. https://github.com/bcgit/bc-java/issues/1590. - // There may be a flags sub-list here for ed25519 or curve25519. - if (type.equals("flags")) { - SXprUtils.readString(inputStream, inputStream.read()); - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipOpenParenthesis(inputStream); - type = SXprUtils.readString(inputStream, - inputStream.read()); - } - if (type.equals("q")) { - qVal = SXprUtils.readBytes(inputStream, inputStream.read()); - } else { - throw new PGPException("no q value found"); - } - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.ECDSA, new Date(), - new ECDSAPublicBCPGKey( - ECNamedCurveTable.getOID(curveName), - new BigInteger(1, qVal))); - - SXprUtils.skipCloseParenthesis(inputStream); - - BigInteger d = processECSecretKey(inputStream, curveID, - curveName, qVal, keyProtectionRemoverFactory); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new ECSecretBCPGKey(d).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("dsa")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger q = readBigInteger("q", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processDSASecretKey(inputStream, p, q, g, y, - keyProtectionRemoverFactory); - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.DSA, new Date(), - new DSAPublicBCPGKey(p, q, g, y)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new DSASecretBCPGKey(x).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("elg")) { - BigInteger p = readBigInteger("p", inputStream); - BigInteger g = readBigInteger("g", inputStream); - - BigInteger y = readBigInteger("y", inputStream); - - BigInteger x = processElGamalSecretKey(inputStream, p, g, y, - keyProtectionRemoverFactory); - - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT, new Date(), - new ElGamalPublicBCPGKey(p, g, y)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new ElGamalSecretBCPGKey(x).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else if (keyType.equals("rsa")) { - BigInteger n = readBigInteger("n", inputStream); - BigInteger e = readBigInteger("e", inputStream); - - BigInteger[] values = processRSASecretKey(inputStream, n, e, - keyProtectionRemoverFactory); - - // TODO: type of RSA key? - PublicKeyPacket pubPacket = new PublicKeyPacket( - PublicKeyAlgorithmTags.RSA_GENERAL, new Date(), - new RSAPublicBCPGKey(n, e)); - - return new PGPSecretKey( - new SecretKeyPacket(pubPacket, - SymmetricKeyAlgorithmTags.NULL, null, null, - new RSASecretBCPGKey(values[0], values[1], - values[2]).getEncoded()), - new PGPPublicKey(pubPacket, fingerPrintCalculator)); - } else { - throw new PGPException("unknown key type: " + keyType); - } - } - - throw new PGPException("unknown key type found"); - } - - private BigInteger readBigInteger(String expectedType, - InputStream inputStream) throws IOException, PGPException { - SXprUtils.skipOpenParenthesis(inputStream); - - String type = SXprUtils.readString(inputStream, inputStream.read()); - if (!type.equals(expectedType)) { - throw new PGPException(expectedType + " value expected"); - } - - byte[] nBytes = SXprUtils.readBytes(inputStream, inputStream.read()); - BigInteger v = new BigInteger(1, nBytes); - - SXprUtils.skipCloseParenthesis(inputStream); - - return v; - } - - private static byte[][] extractData(InputStream inputStream, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws PGPException, IOException { - byte[] data; - byte[] protectedAt = null; - - SXprUtils.skipOpenParenthesis(inputStream); - - String type = SXprUtils.readString(inputStream, inputStream.read()); - if (type.equals("protected")) { - String protection = SXprUtils.readString(inputStream, - inputStream.read()); - - SXprUtils.skipOpenParenthesis(inputStream); - - S2K s2k = SXprUtils.parseS2K(inputStream); - - byte[] iv = SXprUtils.readBytes(inputStream, inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - byte[] secKeyData = SXprUtils.readBytes(inputStream, - inputStream.read()); - - SXprUtils.skipCloseParenthesis(inputStream); - - PBESecretKeyDecryptor keyDecryptor = keyProtectionRemoverFactory - .createDecryptor(protection); - - // TODO: recognise other algorithms - byte[] key = keyDecryptor.makeKeyFromPassPhrase( - SymmetricKeyAlgorithmTags.AES_128, s2k); - - data = keyDecryptor.recoverKeyData( - SymmetricKeyAlgorithmTags.AES_128, key, iv, secKeyData, 0, - secKeyData.length); - - // check if protected at is present - if (inputStream.read() == '(') { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - - bOut.write('('); - int ch; - while ((ch = inputStream.read()) >= 0 && ch != ')') { - bOut.write(ch); - } - - if (ch != ')') { - throw new IOException("unexpected end to SExpr"); - } - - bOut.write(')'); - - protectedAt = bOut.toByteArray(); - } - - SXprUtils.skipCloseParenthesis(inputStream); - SXprUtils.skipCloseParenthesis(inputStream); - } else if (type.equals("d") || type.equals("x")) { - // JGit modification: unencrypted DSA or ECC keys can have an "x" - // here - return null; - } else { - throw new PGPException("protected block not found"); - } - - return new byte[][] { data, protectedAt }; - } - - private BigInteger processDSASecretKey(InputStream inputStream, - BigInteger p, BigInteger q, BigInteger g, BigInteger y, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted DSA keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger x = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return x; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - - BigInteger x = readBigInteger("x", keyIn); - - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return x; - } - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:dsa")); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "q", q); - writeCanonical(dOut, "g", g); - writeCanonical(dOut, "y", y); - writeCanonical(dOut, "x", x); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return x; - } - - private BigInteger processElGamalSecretKey(InputStream inputStream, - BigInteger p, BigInteger g, BigInteger y, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted EC keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger x = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return x; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - - BigInteger x = readBigInteger("x", keyIn); - - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return x; - } - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:elg")); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "g", g); - writeCanonical(dOut, "y", y); - writeCanonical(dOut, "x", x); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return x; - } - - private BigInteger processECSecretKey(InputStream inputStream, - String curveID, String curveName, byte[] qVal, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - // JGit modification: handle unencrypted EC keys - if (basicData == null) { - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - BigInteger d = new BigInteger(1, nBytes); - SXprUtils.skipCloseParenthesis(inputStream); - return d; - } - - byte[] keyData = basicData[0]; - byte[] protectedAt = basicData[1]; - - // - // parse the secret key S-expr - // - InputStream keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - BigInteger d = readBigInteger("d", keyIn); - SXprUtils.skipCloseParenthesis(keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return d; - } - - SXprUtils.skipOpenParenthesis(keyIn); - - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:ecc")); - - dOut.write(Strings.toByteArray("(" + curveID.length() + ":" - + curveID + curveName.length() + ":" + curveName + ")")); - - writeCanonical(dOut, "q", qVal); - writeCanonical(dOut, "d", d); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return d; - } - - private BigInteger[] processRSASecretKey(InputStream inputStream, - BigInteger n, BigInteger e, - PBEProtectionRemoverFactory keyProtectionRemoverFactory) - throws IOException, PGPException { - String type; - byte[][] basicData = extractData(inputStream, - keyProtectionRemoverFactory); - - byte[] keyData; - byte[] protectedAt = null; - - InputStream keyIn; - BigInteger d; - - if (basicData == null) { - keyIn = inputStream; - byte[] nBytes = SXprUtils.readBytes(inputStream, - inputStream.read()); - d = new BigInteger(1, nBytes); - - SXprUtils.skipCloseParenthesis(inputStream); - - } else { - keyData = basicData[0]; - protectedAt = basicData[1]; - - keyIn = new ByteArrayInputStream(keyData); - - SXprUtils.skipOpenParenthesis(keyIn); - SXprUtils.skipOpenParenthesis(keyIn); - d = readBigInteger("d", keyIn); - } - - // - // parse the secret key S-expr - // - - BigInteger p = readBigInteger("p", keyIn); - BigInteger q = readBigInteger("q", keyIn); - BigInteger u = readBigInteger("u", keyIn); - - // JGit modification: OCB-encrypted keys don't have and don't need a - // hash - if (basicData == null - || keyProtectionRemoverFactory instanceof OCBPBEProtectionRemoverFactory) { - return new BigInteger[] { d, p, q, u }; - } - - SXprUtils.skipCloseParenthesis(keyIn); - - SXprUtils.skipOpenParenthesis(keyIn); - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("hash")) { - throw new PGPException("hash keyword expected"); - } - type = SXprUtils.readString(keyIn, keyIn.read()); - - if (!type.equals("sha1")) { - throw new PGPException("hash keyword expected"); - } - - byte[] hashBytes = SXprUtils.readBytes(keyIn, keyIn.read()); - - SXprUtils.skipCloseParenthesis(keyIn); - - if (digestProvider != null) { - PGPDigestCalculator digestCalculator = digestProvider - .get(HashAlgorithmTags.SHA1); - - OutputStream dOut = digestCalculator.getOutputStream(); - - dOut.write(Strings.toByteArray("(3:rsa")); - - writeCanonical(dOut, "n", n); - writeCanonical(dOut, "e", e); - writeCanonical(dOut, "d", d); - writeCanonical(dOut, "p", p); - writeCanonical(dOut, "q", q); - writeCanonical(dOut, "u", u); - - // check protected-at - if (protectedAt != null) { - dOut.write(protectedAt); - } - - dOut.write(Strings.toByteArray(")")); - - byte[] check = digestCalculator.getDigest(); - - if (!Arrays.constantTimeAreEqual(check, hashBytes)) { - throw new PGPException( - "checksum on protected data failed in SExpr"); - } - } - - return new BigInteger[] { d, p, q, u }; - } - - private void writeCanonical(OutputStream dOut, String label, BigInteger i) - throws IOException { - writeCanonical(dOut, label, i.toByteArray()); - } - - private void writeCanonical(OutputStream dOut, String label, byte[] data) - throws IOException { - dOut.write(Strings.toByteArray( - "(" + label.length() + ":" + label + data.length + ":")); - dOut.write(data); - dOut.write(Strings.toByteArray(")")); - } -} diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java deleted file mode 100644 index 220aa285ff..0000000000 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SXprUtils.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2000-2021 The Legion of the Bouncy Castle Inc. (https://www.bouncycastle.org) - * <p> - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - *including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * </p> - * <p> - * The above copyright notice and this permission notice shall be included in all copies or substantial - * portions of the Software. - * </p> - * <p> - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR - * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR - * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * </p> - */ -package org.eclipse.jgit.gpg.bc.internal.keys; - -// This class is an unmodified copy from Bouncy Castle; needed because it's package-visible only and used by SExprParser. - -import java.io.IOException; -import java.io.InputStream; - -import org.bouncycastle.bcpg.HashAlgorithmTags; -import org.bouncycastle.bcpg.S2K; -import org.bouncycastle.util.io.Streams; - -/** - * Utility functions for looking a S-expression keys. This class will move when - * it finds a better home! - * <p> - * Format documented here: - * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master - * </p> - */ -class SXprUtils { - private static int readLength(InputStream in, int ch) throws IOException { - int len = ch - '0'; - - while ((ch = in.read()) >= 0 && ch != ':') { - len = len * 10 + ch - '0'; - } - - return len; - } - - static String readString(InputStream in, int ch) throws IOException { - int len = readLength(in, ch); - - char[] chars = new char[len]; - - for (int i = 0; i != chars.length; i++) { - chars[i] = (char) in.read(); - } - - return new String(chars); - } - - static byte[] readBytes(InputStream in, int ch) throws IOException { - int len = readLength(in, ch); - - byte[] data = new byte[len]; - - Streams.readFully(in, data); - - return data; - } - - static S2K parseS2K(InputStream in) throws IOException { - skipOpenParenthesis(in); - - // Algorithm is hard-coded to SHA1 below anyway. - readString(in, in.read()); - byte[] iv = readBytes(in, in.read()); - final long iterationCount = Long.parseLong(readString(in, in.read())); - - skipCloseParenthesis(in); - - // we have to return the actual iteration count provided. - S2K s2k = new S2K(HashAlgorithmTags.SHA1, iv, (int) iterationCount) { - @Override - public long getIterationCount() { - return iterationCount; - } - }; - - return s2k; - } - - static void skipOpenParenthesis(InputStream in) throws IOException { - int ch = in.read(); - if (ch != '(') { - throw new IOException( - "unknown character encountered: " + (char) ch); //$NON-NLS-1$ - } - } - - static void skipCloseParenthesis(InputStream in) throws IOException { - int ch = in.read(); - if (ch != ')') { - throw new IOException("unknown character encountered"); //$NON-NLS-1$ - } - } -} diff --git a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java index a659d38fd3..a56e418bf4 100644 --- a/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java +++ b/org.eclipse.jgit.gpg.bc/src/org/eclipse/jgit/gpg/bc/internal/keys/SecretKeys.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * Copyright (C) 2021, 2024 Thomas Wolf <twolf@apache.org> and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -9,34 +9,36 @@ */ package org.eclipse.jgit.gpg.bc.internal.keys; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.EOFException; +import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.StreamCorruptedException; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.text.MessageFormat; -import java.util.Arrays; +import org.bouncycastle.bcpg.ECPublicBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.gpg.PGPSecretKeyParser; +import org.bouncycastle.gpg.SExprParser; +import org.bouncycastle.openpgp.OpenedPGPKeyData; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.operator.PBEProtectionRemoverFactory; import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; +import org.bouncycastle.openpgp.operator.jcajce.JcaKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.jcajce.JcePBEProtectionRemoverFactory; -import org.bouncycastle.util.io.Streams; import org.eclipse.jgit.api.errors.CanceledException; import org.eclipse.jgit.errors.UnsupportedCredentialItem; import org.eclipse.jgit.gpg.bc.internal.BCText; -import org.eclipse.jgit.util.RawParseUtils; /** * Utilities for reading GPG secret keys from a gpg-agent key file. */ public final class SecretKeys { + // Maximum nesting depth of sub-lists in an S-Expression for a secret key. + private static final int MAX_SEXPR_NESTING = 20; + private SecretKeys() { // No instantiation. } @@ -64,12 +66,6 @@ public final class SecretKeys { UnsupportedCredentialItem, URISyntaxException; } - private static final byte[] PROTECTED_KEY = "protected-private-key" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - - private static final byte[] OCB_PROTECTED = "openpgp-s2k3-ocb-aes" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - /** * Reads a GPG secret key from the given stream. * @@ -99,500 +95,59 @@ public final class SecretKeys { PassphraseSupplier passphraseSupplier, PGPPublicKey publicKey) throws IOException, PGPException, CanceledException, UnsupportedCredentialItem, URISyntaxException { - byte[] data = Streams.readAll(in); - if (data.length == 0) { - throw new EOFException(); - } else if (data.length < 4 + PROTECTED_KEY.length) { - // +4 for "(21:" for a binary protected key - throw new IOException( - MessageFormat.format(BCText.get().secretKeyTooShort, - Integer.toUnsignedString(data.length))); - } - SExprParser parser = new SExprParser(calculatorProvider); - byte firstChar = data[0]; - try { - if (firstChar == '(') { - // Binary format. - PBEProtectionRemoverFactory decryptor = null; - if (matches(data, 4, PROTECTED_KEY)) { - // AES/CBC encrypted. - decryptor = new JcePBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider); - } - try (InputStream sIn = new ByteArrayInputStream(data)) { - return parser.parseSecretKey(sIn, decryptor, publicKey); - } - } - // Assume it's the new key-value format. - try (ByteArrayInputStream keyIn = new ByteArrayInputStream(data)) { - byte[] rawData = keyFromNameValueFormat(keyIn); - if (!matches(rawData, 1, PROTECTED_KEY)) { - // Not encrypted human-readable format. - try (InputStream sIn = new ByteArrayInputStream( - convertSexpression(rawData))) { - return parser.parseSecretKey(sIn, null, publicKey); - } - } - // An encrypted key from a key-value file. Most likely AES/OCB - // encrypted. - boolean isOCB[] = { false }; - byte[] sExp = convertSexpression(rawData, isOCB); - PBEProtectionRemoverFactory decryptor; - if (isOCB[0]) { - decryptor = new OCBPBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider, getAad(sExp)); - } else { - decryptor = new JcePBEProtectionRemoverFactory( - passphraseSupplier.getPassphrase(), - calculatorProvider); - } - try (InputStream sIn = new ByteArrayInputStream(sExp)) { - return parser.parseSecretKey(sIn, decryptor, publicKey); - } - } - } catch (IOException e) { - throw new PGPException(e.getLocalizedMessage(), e); - } - } - - /** - * Extract the AAD for the OCB decryption from an s-expression. - * - * @param sExp - * buffer containing a valid binary s-expression - * @return the AAD - */ - private static byte[] getAad(byte[] sExp) { - // Given a key - // @formatter:off - // (protected-private-key (rsa ... (protected openpgp-s2k3-ocb-aes ... )(protected-at ...))) - // A B C D - // The AAD is [A..B)[C..D). (From the binary serialized form.) - // @formatter:on - int i = 1; // Skip initial '(' - while (sExp[i] != '(') { - i++; - } - int aadStart = i++; - int aadEnd = skip(sExp, aadStart); - byte[] protectedPrefix = "(9:protected" //$NON-NLS-1$ - .getBytes(StandardCharsets.US_ASCII); - while (!matches(sExp, i, protectedPrefix)) { - i++; - } - int protectedStart = i; - int protectedEnd = skip(sExp, protectedStart); - byte[] aadData = new byte[aadEnd - aadStart - - (protectedEnd - protectedStart)]; - System.arraycopy(sExp, aadStart, aadData, 0, protectedStart - aadStart); - System.arraycopy(sExp, protectedEnd, aadData, protectedStart - aadStart, - aadEnd - protectedEnd); - return aadData; - } - - /** - * Skips a list including nested lists. - * - * @param sExp - * buffer containing valid binary s-expression data - * @param start - * index of the opening '(' of the list to skip - * @return the index after the closing ')' of the skipped list - */ - private static int skip(byte[] sExp, int start) { - int i = start + 1; - int depth = 1; - while (depth > 0) { - switch (sExp[i]) { - case '(': - depth++; - break; - case ')': - depth--; - break; - default: - // We must be on a length - int j = i; - while (sExp[j] >= '0' && sExp[j] <= '9') { - j++; - } - // j is on the colon - int length = Integer.parseInt( - new String(sExp, i, j - i, StandardCharsets.US_ASCII)); - i = j + length; - } - i++; - } - return i; - } - - /** - * Checks whether the {@code needle} matches {@code src} at offset - * {@code from}. - * - * @param src - * to match against {@code needle} - * @param from - * position in {@code src} to start matching - * @param needle - * to match against - * @return {@code true} if {@code src} contains {@code needle} at position - * {@code from}, {@code false} otherwise - */ - private static boolean matches(byte[] src, int from, byte[] needle) { - if (from < 0 || from + needle.length > src.length) { - return false; - } - return org.bouncycastle.util.Arrays.constantTimeAreEqual(needle.length, - src, from, needle, 0); - } - - /** - * Converts a human-readable serialized s-expression into a binary - * serialized s-expression. - * - * @param humanForm - * to convert - * @return the converted s-expression - * @throws IOException - * if the conversion fails - */ - private static byte[] convertSexpression(byte[] humanForm) - throws IOException { - boolean[] isOCB = { false }; - return convertSexpression(humanForm, isOCB); - } - - /** - * Converts a human-readable serialized s-expression into a binary - * serialized s-expression. - * - * @param humanForm - * to convert - * @param isOCB - * returns whether the s-expression specified AES/OCB encryption - * @return the converted s-expression - * @throws IOException - * if the conversion fails - */ - private static byte[] convertSexpression(byte[] humanForm, boolean[] isOCB) - throws IOException { - int pos = 0; - try (ByteArrayOutputStream out = new ByteArrayOutputStream( - humanForm.length)) { - while (pos < humanForm.length) { - byte b = humanForm[pos]; - if (b == '(' || b == ')') { - out.write(b); - pos++; - } else if (isGpgSpace(b)) { - pos++; - } else if (b == '#') { - // Hex value follows up to the next # - int i = ++pos; - while (i < humanForm.length && isHex(humanForm[i])) { - i++; - } - if (i == pos || humanForm[i] != '#') { - throw new StreamCorruptedException( - BCText.get().sexprHexNotClosed); - } - if ((i - pos) % 2 != 0) { - throw new StreamCorruptedException( - BCText.get().sexprHexOdd); - } - int l = (i - pos) / 2; - out.write(Integer.toString(l) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - while (pos < i) { - int x = (nibble(humanForm[pos]) << 4) - | nibble(humanForm[pos + 1]); - pos += 2; - out.write(x); - } - pos = i + 1; - } else if (isTokenChar(b)) { - // Scan the token - int start = pos++; - while (pos < humanForm.length - && isTokenChar(humanForm[pos])) { - pos++; - } - int l = pos - start; - if (pos - start == OCB_PROTECTED.length - && matches(humanForm, start, OCB_PROTECTED)) { - isOCB[0] = true; - } - out.write(Integer.toString(l) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - out.write(humanForm, start, pos - start); - } else if (b == '"') { - // Potentially quoted string. - int start = ++pos; - boolean escaped = false; - while (pos < humanForm.length - && (escaped || humanForm[pos] != '"')) { - int ch = humanForm[pos++]; - escaped = !escaped && ch == '\\'; - } - if (pos >= humanForm.length) { - throw new StreamCorruptedException( - BCText.get().sexprStringNotClosed); - } - // start is on the first character of the string, pos on the - // closing quote. - byte[] dq = dequote(humanForm, start, pos); - out.write(Integer.toString(dq.length) - .getBytes(StandardCharsets.US_ASCII)); - out.write(':'); - out.write(dq); - pos++; - } else { - throw new StreamCorruptedException( - MessageFormat.format(BCText.get().sexprUnhandled, - Integer.toHexString(b & 0xFF))); - } - } - return out.toByteArray(); + OpenedPGPKeyData data; + try (InputStream keyIn = new BufferedInputStream(in)) { + data = PGPSecretKeyParser.parse(keyIn, MAX_SEXPR_NESTING); } - } - - /** - * GPG-style string de-quoting, which is basically C-style, with some - * literal CR/LF escaping. - * - * @param in - * buffer containing the quoted string - * @param from - * index after the opening quote in {@code in} - * @param to - * index of the closing quote in {@code in} - * @return the dequoted raw string value - * @throws StreamCorruptedException - * if object stream is corrupt - */ - private static byte[] dequote(byte[] in, int from, int to) - throws StreamCorruptedException { - // Result must be shorter or have the same length - byte[] out = new byte[to - from]; - int j = 0; - int i = from; - while (i < to) { - byte b = in[i++]; - if (b != '\\') { - out[j++] = b; - continue; - } - if (i == to) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidEscapeAtEnd); - } - b = in[i++]; - switch (b) { - case 'b': - out[j++] = '\b'; - break; - case 'f': - out[j++] = '\f'; - break; - case 'n': - out[j++] = '\n'; - break; - case 'r': - out[j++] = '\r'; - break; - case 't': - out[j++] = '\t'; - break; - case 'v': - out[j++] = 0x0B; - break; - case '"': - case '\'': - case '\\': - out[j++] = b; - break; - case '\r': - // Escaped literal line end. If an LF is following, skip that, - // too. - if (i < to && in[i] == '\n') { - i++; - } - break; - case '\n': - // Same for LF possibly followed by CR. - if (i < to && in[i] == '\r') { - i++; - } - break; - case 'x': - if (i + 1 >= to || !isHex(in[i]) || !isHex(in[i + 1])) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidHexEscape); - } - out[j++] = (byte) ((nibble(in[i]) << 4) | nibble(in[i + 1])); - i += 2; - break; - case '0': - case '1': - case '2': - case '3': - if (i + 2 >= to || !isOctal(in[i]) || !isOctal(in[i + 1]) - || !isOctal(in[i + 2])) { - throw new StreamCorruptedException( - BCText.get().sexprStringInvalidOctalEscape); - } - out[j++] = (byte) (((((in[i] - '0') << 3) - | (in[i + 1] - '0')) << 3) | (in[i + 2] - '0')); - i += 3; - break; - default: - throw new StreamCorruptedException(MessageFormat.format( - BCText.get().sexprStringInvalidEscape, - Integer.toHexString(b & 0xFF))); - } + PBEProtectionRemoverFactory decryptor = null; + if (isProtected(data)) { + decryptor = new JcePBEProtectionRemoverFactory( + passphraseSupplier.getPassphrase(), calculatorProvider); } - return Arrays.copyOf(out, j); - } - - /** - * Extracts the key from a GPG name-value-pair key file. - * <p> - * Package-visible for tests only. - * </p> - * - * @param in - * {@link InputStream} to read from; should be buffered - * @return the raw key data as extracted from the file - * @throws IOException - * if the {@code in} stream cannot be read or does not contain a - * key - */ - static byte[] keyFromNameValueFormat(InputStream in) throws IOException { - // It would be nice if we could use RawParseUtils here, but GPG compares - // names case-insensitively. We're only interested in the "Key:" - // name-value pair. - int[] nameLow = { 'k', 'e', 'y', ':' }; - int[] nameCap = { 'K', 'E', 'Y', ':' }; - int nameIdx = 0; - for (;;) { - int next = in.read(); - if (next < 0) { - throw new EOFException(); + switch (publicKey.getAlgorithm()) { + case PublicKeyAlgorithmTags.EDDSA_LEGACY: + case PublicKeyAlgorithmTags.Ed25519: + // If we let Bouncy Castle check whether the secret key matches the + // given public key it may get into trouble in some cases with + // ed25519 keys. It appears that we may end up with secret keys + // using the official RFC 8410 OID for ed25519, "1.3.101.112", while + // the public key passed in may have a non-standard OpenPGP-specific + // OID "1.3.6.1.4.1.11591.15.1", or vice versa. Bouncy Castle then + // throws an exception because of the different OIDs. + // + // The work-around is to just read the secret key, and double-check + // later that the OIDs are compatible and the curve points match. + PGPSecretKey secret = data.getKeyData(null, calculatorProvider, + decryptor, new JcaKeyFingerprintCalculator(), + MAX_SEXPR_NESTING); + PGPPublicKey pubKeyRead = secret.getPublicKey(); + int algoRead = pubKeyRead.getAlgorithm(); + if (algoRead != PublicKeyAlgorithmTags.EDDSA_LEGACY + && algoRead != PublicKeyAlgorithmTags.Ed25519) { + throw new PGPException(BCText.get().keyAlgorithmMismatch); } - if (next == '\n') { - nameIdx = 0; - } else if (nameIdx >= 0) { - if (nameLow[nameIdx] == next || nameCap[nameIdx] == next) { - nameIdx++; - if (nameIdx == nameLow.length) { - break; - } - } else { - nameIdx = -1; - } - } - } - // We're after "Key:". Read the value as continuation lines. - int last = ':'; - byte[] rawData; - try (ByteArrayOutputStream out = new ByteArrayOutputStream(8192)) { - for (;;) { - int next = in.read(); - if (next < 0) { - break; - } - if (last == '\n') { - if (next == ' ' || next == '\t') { - // Continuation line; skip this whitespace - last = next; - continue; - } - break; // Not a continuation line - } - out.write(next); - last = next; + ECPublicBCPGKey ec1 = (ECPublicBCPGKey) publicKey + .getPublicKeyPacket().getKey(); + ECPublicBCPGKey ec2 = (ECPublicBCPGKey) pubKeyRead + .getPublicKeyPacket().getKey(); + if (!ObjectIds.match(ec1.getCurveOID(), ec2.getCurveOID()) + || !ec1.getEncodedPoint().equals(ec2.getEncodedPoint())) { + throw new PGPException( + MessageFormat.format(BCText.get().keyMismatch, + ec1.getCurveOID(), ec1.getEncodedPoint(), + ec2.getCurveOID(), ec2.getEncodedPoint())); } - rawData = out.toByteArray(); - } - // GPG trims off trailing whitespace, and a line having only whitespace - // is a single LF. - try (ByteArrayOutputStream out = new ByteArrayOutputStream( - rawData.length)) { - int lineStart = 0; - boolean trimLeading = true; - while (lineStart < rawData.length) { - int nextLineStart = RawParseUtils.nextLF(rawData, lineStart); - if (trimLeading) { - while (lineStart < nextLineStart - && isGpgSpace(rawData[lineStart])) { - lineStart++; - } - } - // Trim trailing - int i = nextLineStart - 1; - while (lineStart < i && isGpgSpace(rawData[i])) { - i--; - } - if (i <= lineStart) { - // Empty line signifies LF - out.write('\n'); - trimLeading = true; - } else { - out.write(rawData, lineStart, i - lineStart + 1); - trimLeading = false; - } - lineStart = nextLineStart; - } - return out.toByteArray(); - } - } - - private static boolean isGpgSpace(int ch) { - return ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n'; - } - - private static boolean isTokenChar(int ch) { - switch (ch) { - case '-': - case '.': - case '/': - case '_': - case ':': - case '*': - case '+': - case '=': - return true; + return secret; default: - if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') - || (ch >= '0' && ch <= '9')) { - return true; - } - return false; + // For other key types let Bouncy Castle do the check. + return data.getKeyData(publicKey, calculatorProvider, decryptor, + null, MAX_SEXPR_NESTING); } } - private static boolean isHex(int ch) { - return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') - || (ch >= 'a' && ch <= 'f'); + private static boolean isProtected(OpenedPGPKeyData data) { + return SExprParser.ProtectionFormatTypeTags.PROTECTED_PRIVATE_KEY == SExprParser + .getProtectionType(data.getKeyExpression().getString(0)); } - private static boolean isOctal(int ch) { - return (ch >= '0' && ch <= '7'); - } - - private static int nibble(int ch) { - if (ch >= '0' && ch <= '9') { - return ch - '0'; - } else if (ch >= 'A' && ch <= 'F') { - return ch - 'A' + 10; - } else if (ch >= 'a' && ch <= 'f') { - return ch - 'a' + 10; - } - return -1; - } } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index 419fdb1966..b0365aa7e1 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -18,6 +18,9 @@ import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Duration; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -202,6 +205,11 @@ public class MockSystemReader extends SystemReader { } @Override + public Instant now() { + return Instant.ofEpochMilli(now); + } + + @Override public MonotonicClock getClock() { return () -> { long t = getCurrentTime(); @@ -237,11 +245,21 @@ public class MockSystemReader extends SystemReader { } @Override + public ZoneOffset getTimeZoneAt(Instant when) { + return getTimeZoneId().getRules().getOffset(when); + } + + @Override public TimeZone getTimeZone() { return TimeZone.getTimeZone("GMT-03:30"); } @Override + public ZoneId getTimeZoneId() { + return ZoneOffset.ofHoursMinutes(-3, 30); + } + + @Override public Locale getLocale() { return Locale.US; } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java index c8c56b21b8..2a482df04a 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java @@ -44,7 +44,7 @@ public class SeparateClassloaderTestRunner extends BlockJUnit4ClassRunner { try { String pathSeparator = System.getProperty("path.separator"); String[] classPathEntries = System.getProperty("java.class.path") - .split(pathSeparator); + .split(pathSeparator, -1); URL[] urls = new URL[classPathEntries.length]; for (int i = 0; i < classPathEntries.length; i++) { urls[i] = Paths.get(classPathEntries[i]).toUri().toURL(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index a2e0a571eb..66cf739ef1 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Set; import java.util.TimeZone; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -1144,15 +1145,18 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } /** - * set parent commit + * Set parent commit * * @param p - * parent commit + * parent commit, can be {@code null} * @return this commit builder * @throws Exception * if an error occurred */ - public CommitBuilder parent(RevCommit p) throws Exception { + public CommitBuilder parent(@Nullable RevCommit p) throws Exception { + if (p == null) { + return this; + } if (parents.isEmpty()) { DirCacheBuilder b = tree.builder(); parseBody(p); diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target index d2006b8d60..623e964217 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.17.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.17" sequenceNumber="1728509927"> +<target name="jgit-4.17" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target index 882f4e1313..66d68e06f2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.18.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.18" sequenceNumber="1728509927"> +<target name="jgit-4.18" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target index 60e0f8f76f..16b9706b3e 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.19.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.19-staging" sequenceNumber="1728509927"> +<target name="jgit-4.19-staging" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target index b0601e8909..9604132842 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.20.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.20" sequenceNumber="1728509927"> +<target name="jgit-4.20" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target index bd3625d4f5..78149754b4 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.21.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.21" sequenceNumber="1728509927"> +<target name="jgit-4.21" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target index 5006956a61..b5fcaf31dc 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.22.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.22" sequenceNumber="1728509926"> +<target name="jgit-4.22" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target index 68124f196b..b57ac90a93 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.23.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.23" sequenceNumber="1728509926"> +<target name="jgit-4.23" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target index 9d26a8930c..dd7081e0ae 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.24.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.24" sequenceNumber="1728509926"> +<target name="jgit-4.24" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target index 6ad784208f..e5cbf9b35a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.25.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.25" sequenceNumber="1728509926"> +<target name="jgit-4.25" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target index 8bff6b28c2..48ffc2f27f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.26.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.26" sequenceNumber="1728509924"> +<target name="jgit-4.26" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target index ef4a71aa3e..5c7e1a4596 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.27.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.27" sequenceNumber="1728509924"> +<target name="jgit-4.27" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target index 14e81823c9..735d1cf5c9 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.28.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.28" sequenceNumber="1728509924"> +<target name="jgit-4.28" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target index 7e121c4d2a..9357dee548 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.29.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.29" sequenceNumber="1728509924"> +<target name="jgit-4.29" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target index 2ccc22db58..295b9c3c46 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.30.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.30" sequenceNumber="1728509924"> +<target name="jgit-4.30" sequenceNumber="1730768367"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target index dfedead946..b9b690ccca 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.31.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.31" sequenceNumber="1728509924"> +<target name="jgit-4.31" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target index 96ed4f1b80..2407a8708f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.32.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.32" sequenceNumber="1728509922"> +<target name="jgit-4.32" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target index 8b4a174f12..78433361fe 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.33.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.33" sequenceNumber="1728509922"> +<target name="jgit-4.33" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target index 2ec0ba4fa6..c913b9dcca 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.34.target @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> <?pde?> <!-- generated with https://github.com/eclipse-cbi/targetplatform-dsl --> -<target name="jgit-4.34" sequenceNumber="1728509925"> +<target name="jgit-4.34" sequenceNumber="1730768368"> <locations> <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit"> <unit id="com.jcraft.jsch" version="0.1.55.v20230916-1400"/> @@ -79,7 +79,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> <type>jar</type> </dependency> </dependencies> @@ -193,13 +193,13 @@ <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> <dependency> <groupId>net.bytebuddy</groupId> <artifactId>byte-buddy-agent</artifactId> - <version>1.15.3</version> + <version>1.15.10</version> <type>jar</type> </dependency> </dependencies> @@ -209,25 +209,25 @@ <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpg-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcutil-jdk18on</artifactId> - <version>1.78.1</version> + <version>1.79</version> <type>jar</type> </dependency> </dependencies> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd index e2889b87c6..68b457c0f3 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/maven/dependencies.tpd @@ -69,22 +69,22 @@ maven bouncycastle dependency { groupId = "org.bouncycastle" artifactId = "bcpg-jdk18on" - version = "1.78.1" + version = "1.79" } dependency { groupId = "org.bouncycastle" artifactId = "bcprov-jdk18on" - version = "1.78.1" + version = "1.79" } dependency { groupId = "org.bouncycastle" artifactId = "bcpkix-jdk18on" - version = "1.78.1" + version = "1.79" } dependency { groupId = "org.bouncycastle" artifactId = "bcutil-jdk18on" - version = "1.78.1" + version = "1.79" } } @@ -97,12 +97,12 @@ maven bytebuddy dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy" - version = "1.15.3" + version = "1.15.10" } dependency { groupId = "net.bytebuddy" artifactId = "byte-buddy-agent" - version = "1.15.3" + version = "1.15.10" } } @@ -225,7 +225,7 @@ maven mockito dependency { groupId = "org.mockito" artifactId = "mockito-core" - version = "5.14.1" + version = "5.14.2" } } diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java index aacde2f430..a29c4d9f36 100644 --- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java +++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/MergeBase.java @@ -26,11 +26,6 @@ class MergeBase extends TextBuiltin { private boolean all; @Argument(index = 0, metaVar = "metaVar_commitish", required = true) - void commit_0(final RevCommit c) { - commits.add(c); - } - - @Argument(index = 1, metaVar = "metaVar_commitish", required = true) private List<RevCommit> commits = new ArrayList<>(); @Override diff --git a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java index 6a0cec8821..f4eb884239 100644 --- a/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java +++ b/org.eclipse.jgit.ssh.apache/src/org/eclipse/jgit/internal/signing/ssh/SerialRangeSet.java @@ -9,7 +9,6 @@ */ package org.eclipse.jgit.internal.signing.ssh; -import java.util.SortedMap; import java.util.TreeMap; import org.eclipse.jgit.internal.transport.sshd.SshdText; @@ -50,14 +49,14 @@ class SerialRangeSet { } } - // We use the same data structure as OpenSSH,; basically a - // TreeSet<SerialRange> of mutable elements. To get "mutability", the set is - // implemented as a TreeMap with the same elements as keys and values. + // We use the same data structure as OpenSSH; basically a TreeSet of mutable + // SerialRanges. To get "mutability", the set is implemented as a TreeMap + // with the same elements as keys and values. // // get(x) will return null if none of the serial numbers in the range x is // in the set, and some range (partially) overlapping with x otherwise. // - // containsKey will return true if there is any (partially) overlapping + // containsKey(x) will return true if there is any (partially) overlapping // range in the TreeMap. private final TreeMap<SerialRange, SerialRange> ranges = new TreeMap<>( SerialRangeSet::compare); @@ -117,21 +116,15 @@ class SerialRangeSet { } // No overlapping range exists: check for coalescing with the // previous/next range - SortedMap<SerialRange, SerialRange> head = ranges.headMap(newRange); - if (!head.isEmpty()) { - SerialRange prev = head.lastKey(); - if (newRange.from() - prev.to() == 1) { - ranges.remove(prev); - newRange = new Range(prev.from(), newRange.to()); - } + SerialRange prev = ranges.floorKey(newRange); + if (prev != null && newRange.from() - prev.to() == 1) { + ranges.remove(prev); + newRange = new Range(prev.from(), newRange.to()); } - SortedMap<SerialRange, SerialRange> tail = ranges.tailMap(newRange); - if (!tail.isEmpty()) { - SerialRange next = tail.firstKey(); - if (next.from() - newRange.to() == 1) { - ranges.remove(next); - newRange = new Range(newRange.from(), next.to()); - } + SerialRange next = ranges.ceilingKey(newRange); + if (next != null && next.from() - newRange.to() == 1) { + ranges.remove(next); + newRange = new Range(newRange.from(), next.to()); } ranges.put(newRange, newRange); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java deleted file mode 100644 index d0fbdbd090..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerMissingPermissionsTest.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2019 Alex Jitianu <alex_jitianu@sync.ro> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.api; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.security.Policy; -import java.util.Collections; - -import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.util.FileUtils; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * Tests that using a SecurityManager does not result in errors logged. - */ -public class SecurityManagerMissingPermissionsTest extends RepositoryTestCase { - - /** - * Collects all logging sent to the logging system. - */ - private final ByteArrayOutputStream errorOutput = new ByteArrayOutputStream(); - - private SecurityManager originalSecurityManager; - - private PrintStream defaultErrorOutput; - - @Override - @Before - public void setUp() throws Exception { - originalSecurityManager = System.getSecurityManager(); - - // slf4j-simple logs to System.err, redirect it to enable asserting - // logged errors - defaultErrorOutput = System.err; - System.setErr(new PrintStream(errorOutput)); - - refreshPolicyAllPermission(Policy.getPolicy()); - System.setSecurityManager(new SecurityManager()); - super.setUp(); - } - - /** - * If a SecurityManager is active a lot of {@link java.io.FilePermission} - * errors are thrown and logged while initializing a repository. - * - * @throws Exception - */ - @Test - public void testCreateNewRepos_MissingPermissions() throws Exception { - File wcTree = new File(getTemporaryDirectory(), - "CreateNewRepositoryTest_testCreateNewRepos"); - - File marker = new File(getTemporaryDirectory(), "marker"); - Files.write(marker.toPath(), Collections.singletonList("Can write")); - assertTrue("Can write in test directory", marker.isFile()); - FileUtils.delete(marker); - assertFalse("Can delete in test direcory", marker.exists()); - - Git git = Git.init().setBare(false) - .setDirectory(new File(wcTree.getAbsolutePath())).call(); - - addRepoToClose(git.getRepository()); - - assertEquals("", errorOutput.toString()); - } - - @Override - @After - public void tearDown() throws Exception { - System.setSecurityManager(originalSecurityManager); - System.setErr(defaultErrorOutput); - super.tearDown(); - } - - /** - * Refresh the Java Security Policy. - * - * @param policy - * the policy object - * - * @throws IOException - * if the temporary file that contains the policy could not be - * created - */ - private static void refreshPolicyAllPermission(Policy policy) - throws IOException { - // Starting with an all permissions policy. - String policyString = "grant { permission java.security.AllPermission; };"; - - // Do not use TemporaryFilesFactory, it will create a dependency cycle - Path policyFile = Files.createTempFile("testpolicy", ".txt"); - - try { - Files.write(policyFile, Collections.singletonList(policyString)); - System.setProperty("java.security.policy", - policyFile.toUri().toURL().toString()); - policy.refresh(); - } finally { - try { - Files.delete(policyFile); - } catch (IOException e) { - // Do not log; the test tests for no logging having occurred - e.printStackTrace(); - } - } - } - -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java deleted file mode 100644 index 2b930a1133..0000000000 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/SecurityManagerTest.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2019 Nail Samatov <sanail@yandex.ru> and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ -package org.eclipse.jgit.api; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FilePermission; -import java.io.IOException; -import java.lang.reflect.ReflectPermission; -import java.nio.file.Files; -import java.security.Permission; -import java.security.SecurityPermission; -import java.util.ArrayList; -import java.util.List; -import java.util.PropertyPermission; -import java.util.logging.LoggingPermission; - -import javax.security.auth.AuthPermission; - -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.junit.JGitTestUtil; -import org.eclipse.jgit.junit.MockSystemReader; -import org.eclipse.jgit.junit.SeparateClassloaderTestRunner; -import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.treewalk.TreeWalk; -import org.eclipse.jgit.util.FileUtils; -import org.eclipse.jgit.util.SystemReader; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** - * <p> - * Tests if jgit works if SecurityManager is enabled. - * </p> - * - * <p> - * Note: JGit's classes shouldn't be used before SecurityManager is configured. - * If you use some JGit's class before SecurityManager is replaced then part of - * the code can be invoked outside of our custom SecurityManager and this test - * becomes useless. - * </p> - * - * <p> - * For example the class {@link org.eclipse.jgit.util.FS} is used widely in jgit - * sources. It contains DETECTED static field. At the first usage of the class - * FS the field DETECTED is initialized and during initialization many system - * operations that SecurityManager can forbid are invoked. - * </p> - * - * <p> - * For this reason this test doesn't extend LocalDiskRepositoryTestCase (it uses - * JGit's classes in setUp() method) and other JGit's utility classes. It's done - * to affect SecurityManager as less as possible. - * </p> - * - * <p> - * We use SeparateClassloaderTestRunner to isolate FS.DETECTED field - * initialization between different tests run. - * </p> - */ -@RunWith(SeparateClassloaderTestRunner.class) -public class SecurityManagerTest { - private File root; - - private SecurityManager originalSecurityManager; - - private List<Permission> permissions = new ArrayList<>(); - - @Before - public void setUp() throws Exception { - // Create working directory - SystemReader.setInstance(new MockSystemReader()); - root = Files.createTempDirectory("jgit-security").toFile(); - - // Add system permissions - permissions.add(new RuntimePermission("*")); - permissions.add(new SecurityPermission("*")); - permissions.add(new AuthPermission("*")); - permissions.add(new ReflectPermission("*")); - permissions.add(new PropertyPermission("*", "read,write")); - permissions.add(new LoggingPermission("control", null)); - - permissions.add(new FilePermission( - System.getProperty("java.home") + "/-", "read")); - - String tempDir = System.getProperty("java.io.tmpdir"); - permissions.add(new FilePermission(tempDir, "read,write,delete")); - permissions - .add(new FilePermission(tempDir + "/-", "read,write,delete")); - - // Add permissions to dependent jar files. - String classPath = System.getProperty("java.class.path"); - if (classPath != null) { - for (String path : classPath.split(File.pathSeparator)) { - permissions.add(new FilePermission(path, "read")); - } - } - // Add permissions to jgit class files. - String jgitSourcesRoot = new File(System.getProperty("user.dir")) - .getParent(); - permissions.add(new FilePermission(jgitSourcesRoot + "/-", "read")); - - // Add permissions to working dir for jgit. Our git repositories will be - // initialized and cloned here. - permissions.add(new FilePermission(root.getPath() + "/-", - "read,write,delete,execute")); - - // Replace Security Manager - originalSecurityManager = System.getSecurityManager(); - System.setSecurityManager(new SecurityManager() { - - @Override - public void checkPermission(Permission requested) { - for (Permission permission : permissions) { - if (permission.implies(requested)) { - return; - } - } - - super.checkPermission(requested); - } - }); - } - - @After - public void tearDown() throws Exception { - System.setSecurityManager(originalSecurityManager); - - // Note: don't use this method before security manager is replaced in - // setUp() method. The method uses FS.DETECTED internally and can affect - // the test. - FileUtils.delete(root, FileUtils.RECURSIVE | FileUtils.RETRY); - } - - @Test - public void testInitAndClone() throws IOException, GitAPIException { - File remote = new File(root, "remote"); - File local = new File(root, "local"); - - try (Git git = Git.init().setDirectory(remote).call()) { - JGitTestUtil.write(new File(remote, "hello.txt"), "Hello world!"); - git.add().addFilepattern(".").call(); - git.commit().setMessage("Initial commit").call(); - } - - try (Git git = Git.cloneRepository().setURI(remote.toURI().toString()) - .setDirectory(local).call()) { - assertTrue(new File(local, ".git").exists()); - - JGitTestUtil.write(new File(local, "hi.txt"), "Hi!"); - git.add().addFilepattern(".").call(); - RevCommit commit1 = git.commit().setMessage("Commit on local repo") - .call(); - assertEquals("Commit on local repo", commit1.getFullMessage()); - assertNotNull(TreeWalk.forPath(git.getRepository(), "hello.txt", - commit1.getTree())); - } - - } - -} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java index ac769498e2..2c4b432a01 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStatsTest.java @@ -24,9 +24,10 @@ public class AggregatedBlockCacheStatsTest { @Test public void getName() { BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("name", List.of()); + .fromStatsList(List.of()); - assertThat(aggregatedBlockCacheStats.getName(), equalTo("name")); + assertThat(aggregatedBlockCacheStats.getName(), + equalTo(AggregatedBlockCacheStats.class.getName())); } @Test @@ -46,8 +47,7 @@ public class AggregatedBlockCacheStatsTest { currentSizes[PackExt.INDEX.getPosition()] = 7; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getCurrentSize(), currentSizes); @@ -73,8 +73,7 @@ public class AggregatedBlockCacheStatsTest { hitCounts[PackExt.INDEX.getPosition()] = 7; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getHitCount(), hitCounts); } @@ -99,8 +98,7 @@ public class AggregatedBlockCacheStatsTest { missCounts[PackExt.INDEX.getPosition()] = 7; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getMissCount(), missCounts); } @@ -131,8 +129,7 @@ public class AggregatedBlockCacheStatsTest { totalRequestCounts[PackExt.INDEX.getPosition()] = 14; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getTotalRequestCount(), totalRequestCounts); @@ -160,8 +157,7 @@ public class AggregatedBlockCacheStatsTest { hitRatios[PackExt.INDEX.getPosition()] = 0; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("Name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getHitRatio(), hitRatios); } @@ -186,8 +182,7 @@ public class AggregatedBlockCacheStatsTest { evictions[PackExt.INDEX.getPosition()] = 7; BlockCacheStats aggregatedBlockCacheStats = AggregatedBlockCacheStats - .fromStatsList("Name", - List.of(packStats, bitmapStats, indexStats)); + .fromStatsList(List.of(packStats, bitmapStats, indexStats)); assertArrayEquals(aggregatedBlockCacheStats.getEvictions(), evictions); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java index cb68bbc515..2e2f86bf80 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTableTest.java @@ -1,8 +1,14 @@ package org.eclipse.jgit.internal.storage.dfs; import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheConfig.DEFAULT_NAME; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.isA; + +import java.util.List; import org.junit.Test; @@ -30,7 +36,8 @@ public class ClockBlockCacheTableTest { ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( createBlockCacheConfig()); - assertThat(cacheTable.getBlockCacheStats().getName(), + assertThat(cacheTable.getBlockCacheStats(), hasSize(1)); + assertThat(cacheTable.getBlockCacheStats().get(0).getName(), equalTo(DEFAULT_NAME)); } @@ -39,7 +46,18 @@ public class ClockBlockCacheTableTest { ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( createBlockCacheConfig().setName(NAME)); - assertThat(cacheTable.getBlockCacheStats().getName(), equalTo(NAME)); + assertThat(cacheTable.getBlockCacheStats(), hasSize(1)); + assertThat(cacheTable.getBlockCacheStats().get(0).getName(), + equalTo(NAME)); + } + + @Test + public void getAllBlockCacheStats() { + ClockBlockCacheTable cacheTable = new ClockBlockCacheTable( + createBlockCacheConfig()); + + List<BlockCacheStats> blockCacheStats = cacheTable.getBlockCacheStats(); + assertThat(blockCacheStats, contains(isA(BlockCacheStats.class))); } private static DfsBlockCacheConfig createBlockCacheConfig() { diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java index 65774e6d6c..afa3179cde 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfigTest.java @@ -180,6 +180,76 @@ public class DfsBlockCacheConfigTest { } @Test + public void fromConfig_withExistingCacheHotMap_configWithPackExtConfigsHasHotMaps() { + Config config = new Config(); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + addPackExtConfigEntry(config, "bitmap", List.of(PackExt.BITMAP_INDEX), + /* blockLimit= */ 25 * 1024, /* blockSize= */ 1024); + + addPackExtConfigEntry(config, "index", + List.of(PackExt.INDEX, PackExt.OBJECT_SIZE_INDEX, + PackExt.REVERSE_INDEX), + /* blockLimit= */ 30 * 1024, /* blockSize= */ 1024); + + Map<PackExt, Integer> cacheHotMap = Map.of(PackExt.PACK, 1, + PackExt.BITMAP_INDEX, 2, PackExt.INDEX, 3, PackExt.REFTABLE, 4); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig(); + cacheConfig.setCacheHotMap(cacheHotMap); + cacheConfig.fromConfig(config); + + var configs = cacheConfig.getPackExtCacheConfigurations(); + assertThat(cacheConfig.getCacheHotMap(), is(cacheHotMap)); + assertThat(configs, hasSize(3)); + var packConfig = getConfigForExt(configs, PackExt.PACK); + assertThat(packConfig.getCacheHotMap(), is(Map.of(PackExt.PACK, 1))); + + var bitmapConfig = getConfigForExt(configs, PackExt.BITMAP_INDEX); + assertThat(bitmapConfig.getCacheHotMap(), + is(Map.of(PackExt.BITMAP_INDEX, 2))); + + var indexConfig = getConfigForExt(configs, PackExt.INDEX); + assertThat(indexConfig.getCacheHotMap(), is(Map.of(PackExt.INDEX, 3))); + } + + @Test + public void setCacheHotMap_configWithPackExtConfigs_setsHotMaps() { + Config config = new Config(); + addPackExtConfigEntry(config, "pack", List.of(PackExt.PACK), + /* blockLimit= */ 20 * 512, /* blockSize= */ 512); + + addPackExtConfigEntry(config, "bitmap", List.of(PackExt.BITMAP_INDEX), + /* blockLimit= */ 25 * 1024, /* blockSize= */ 1024); + + addPackExtConfigEntry(config, "index", + List.of(PackExt.INDEX, PackExt.OBJECT_SIZE_INDEX, + PackExt.REVERSE_INDEX), + /* blockLimit= */ 30 * 1024, /* blockSize= */ 1024); + + Map<PackExt, Integer> cacheHotMap = Map.of(PackExt.PACK, 1, + PackExt.BITMAP_INDEX, 2, PackExt.INDEX, 3, PackExt.REFTABLE, 4); + + DfsBlockCacheConfig cacheConfig = new DfsBlockCacheConfig() + .fromConfig(config); + cacheConfig.setCacheHotMap(cacheHotMap); + + var configs = cacheConfig.getPackExtCacheConfigurations(); + assertThat(cacheConfig.getCacheHotMap(), is(cacheHotMap)); + assertThat(configs, hasSize(3)); + var packConfig = getConfigForExt(configs, PackExt.PACK); + assertThat(packConfig.getCacheHotMap(), is(Map.of(PackExt.PACK, 1))); + + var bitmapConfig = getConfigForExt(configs, PackExt.BITMAP_INDEX); + assertThat(bitmapConfig.getCacheHotMap(), + is(Map.of(PackExt.BITMAP_INDEX, 2))); + + var indexConfig = getConfigForExt(configs, PackExt.INDEX); + assertThat(indexConfig.getCacheHotMap(), is(Map.of(PackExt.INDEX, 3))); + } + + @Test public void fromConfigs_baseConfigOnly_nameSetFromConfigDfsSubSection() { Config config = new Config(); @@ -291,6 +361,7 @@ public class DfsBlockCacheConfigTest { " Name: dfs.pack", " BlockLimit: " + 20 * 512, " BlockSize: 512", " StreamRatio: 0.3", " ConcurrencyLevel: 32", + " CacheHotMapEntry: " + PackExt.PACK + " : " + 10, " PackExts: " + List.of(PackExt.PACK)))); } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java index 2be11d32ea..f9fbfe8db0 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollectorTest.java @@ -6,6 +6,7 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.IN import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; +import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -15,8 +16,11 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; +import java.time.Instant; import java.util.Arrays; import java.util.Collections; +import java.util.Date; +import java.util.GregorianCalendar; import java.util.concurrent.TimeUnit; import org.eclipse.jgit.internal.storage.commitgraph.CommitGraph; @@ -24,6 +28,7 @@ import org.eclipse.jgit.internal.storage.commitgraph.CommitGraphWriter; import org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource; import org.eclipse.jgit.internal.storage.file.PackBitmapIndex; import org.eclipse.jgit.internal.storage.pack.PackExt; +import org.eclipse.jgit.internal.storage.reftable.LogCursor; import org.eclipse.jgit.internal.storage.reftable.RefCursor; import org.eclipse.jgit.internal.storage.reftable.ReftableConfig; import org.eclipse.jgit.internal.storage.reftable.ReftableReader; @@ -37,6 +42,7 @@ import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdRef; +import org.eclipse.jgit.lib.PersonIdent; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.revwalk.RevBlob; @@ -44,6 +50,7 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.ReceiveCommand; +import org.eclipse.jgit.util.GitDateParser; import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; @@ -1275,6 +1282,90 @@ public class DfsGarbageCollectorTest { bitmapIndex.getXorBitmapCount() > 0); } + @Test + public void gitGCWithRefLogExpire() throws Exception { + String master = "refs/heads/master"; + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update(master, commit1); + DfsGarbageCollector gc = new DfsGarbageCollector(repo); + gc.setReftableConfig(new ReftableConfig()); + run(gc); + DfsPackDescription t1 = odb.newPack(INSERT); + Ref next = new ObjectIdRef.PeeledNonTag(Ref.Storage.LOOSE, + "refs/heads/next", commit0.copy()); + long currentDay = new Date().getTime(); + GregorianCalendar cal = new GregorianCalendar(SystemReader + .getInstance().getTimeZone(), SystemReader.getInstance() + .getLocale()); + long ten_days_ago = GitDateParser.parse("10 days ago",cal,SystemReader.getInstance() + .getLocale()).getTime() ; + long twenty_days_ago = GitDateParser.parse("20 days ago",cal,SystemReader.getInstance() + .getLocale()).getTime() ; + long thirty_days_ago = GitDateParser.parse("30 days ago",cal,SystemReader.getInstance() + .getLocale()).getTime() ;; + long fifty_days_ago = GitDateParser.parse("50 days ago",cal,SystemReader.getInstance() + .getLocale()).getTime() ; + PersonIdent who2 = new PersonIdent("J.Author", "authemail", currentDay, -8 * 60); + PersonIdent who3 = new PersonIdent("J.Author", "authemail", ten_days_ago, -8 * 60); + PersonIdent who4 = new PersonIdent("J.Author", "authemail", twenty_days_ago, -8 * 60); + PersonIdent who5 = new PersonIdent("J.Author", "authemail", thirty_days_ago, -8 * 60); + PersonIdent who6 = new PersonIdent("J.Author", "authemail", fifty_days_ago, -8 * 60); + + try (DfsOutputStream out = odb.writeFile(t1, REFTABLE)) { + ReftableWriter w = new ReftableWriter(out); + w.setMinUpdateIndex(42); + w.setMaxUpdateIndex(42); + w.begin(); + w.sortAndWriteRefs(Collections.singleton(next)); + w.writeLog("refs/heads/branch", 1, who2, ObjectId.zeroId(),id(2), "Branch Message"); + w.writeLog("refs/heads/branch1", 2, who3, ObjectId.zeroId(),id(3), "Branch Message1"); + w.writeLog("refs/heads/branch2", 2, who4, ObjectId.zeroId(),id(4), "Branch Message2"); + w.writeLog("refs/heads/branch3", 2, who5, ObjectId.zeroId(),id(5), "Branch Message3"); + w.writeLog("refs/heads/branch4", 2, who6, ObjectId.zeroId(),id(6), "Branch Message4"); + w.finish(); + t1.addFileExt(REFTABLE); + t1.setReftableStats(w.getStats()); + } + odb.commitPack(Collections.singleton(t1), null); + + gc = new DfsGarbageCollector(repo); + gc.setReftableConfig(new ReftableConfig()); + // Expire ref log entries older than 30 days + gc.setRefLogExpire(Instant.ofEpochMilli(thirty_days_ago)); + run(gc); + + // Single GC pack present with all objects. + assertEquals(1, odb.getPacks().length); + DfsPackFile pack = odb.getPacks()[0]; + DfsPackDescription desc = pack.getPackDescription(); + + DfsReftable table = new DfsReftable(DfsBlockCache.getInstance(), desc); + try (DfsReader ctx = odb.newReader(); + ReftableReader rr = table.open(ctx); + RefCursor rc = rr.allRefs(); + LogCursor lc = rr.allLogs()) { + assertTrue(rc.next()); + assertEquals(master, rc.getRef().getName()); + assertEquals(commit1, rc.getRef().getObjectId()); + assertTrue(rc.next()); + assertEquals(next.getName(), rc.getRef().getName()); + assertEquals(commit0, rc.getRef().getObjectId()); + assertFalse(rc.next()); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch"); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch1"); + assertTrue(lc.next()); + assertEquals(lc.getRefName(),"refs/heads/branch2"); + // Old entries are purged + assertFalse(lc.next()); + + } + + } + + private RevCommit commitChain(RevCommit parent, int length) throws Exception { for (int i = 0; i < length; i++) { @@ -1364,4 +1455,12 @@ public class DfsGarbageCollectorTest { } return cnt; } + private static ObjectId id(int i) { + byte[] buf = new byte[OBJECT_ID_LENGTH]; + buf[0] = (byte) (i & 0xff); + buf[1] = (byte) ((i >>> 8) & 0xff); + buf[2] = (byte) ((i >>> 16) & 0xff); + buf[3] = (byte) (i >>> 24); + return ObjectId.fromRaw(buf); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java index c516e30f50..c3b6aa85a2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsPackCompacterTest.java @@ -12,13 +12,18 @@ package org.eclipse.jgit.internal.storage.dfs; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.INSERT; +import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; +import java.util.Arrays; +import java.util.Optional; import org.eclipse.jgit.junit.TestRepository; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.revwalk.RevCommit; import org.junit.Before; import org.junit.Test; @@ -98,6 +103,40 @@ public class DfsPackCompacterTest { pack.getPackDescription().getEstimatedPackSize()); } + @Test + public void testObjectSizeIndexWritten() throws Exception { + writeObjectSizeIndex(repo, true); + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update("master", commit1); + + compact(); + + Optional<DfsPackFile> compactPack = Arrays.stream(odb.getPacks()) + .filter(pack -> pack.getPackDescription() + .getPackSource() == COMPACT) + .findFirst(); + assertTrue(compactPack.isPresent()); + assertTrue(compactPack.get().getPackDescription().hasFileExt(OBJECT_SIZE_INDEX)); + } + + @Test + public void testObjectSizeIndexNotWritten() throws Exception { + writeObjectSizeIndex(repo, false); + RevCommit commit0 = commit().message("0").create(); + RevCommit commit1 = commit().message("1").parent(commit0).create(); + git.update("master", commit1); + + compact(); + + Optional<DfsPackFile> compactPack = Arrays.stream(odb.getPacks()) + .filter(pack -> pack.getPackDescription() + .getPackSource() == COMPACT) + .findFirst(); + assertTrue(compactPack.isPresent()); + assertFalse(compactPack.get().getPackDescription().hasFileExt(OBJECT_SIZE_INDEX)); + } + private TestRepository<InMemoryRepository>.CommitBuilder commit() { return git.commit(); } @@ -108,4 +147,9 @@ public class DfsPackCompacterTest { compactor.compact(null); odb.clearCache(); } + + private static void writeObjectSizeIndex(DfsRepository repo, boolean should) { + repo.getConfig().setInt(ConfigConstants.CONFIG_PACK_SECTION, null, + ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, should ? 0 : -1); + } } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java index c5c964bcab..e7627bc4ab 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTableTest.java @@ -10,8 +10,10 @@ package org.eclipse.jgit.internal.storage.dfs; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNotNull; @@ -398,15 +400,51 @@ public class PackExtBlockCacheTableTest { } @Test - public void getBlockCacheStats_getName_returnsPackExtCacheTableName() { - DfsBlockCacheStats packStats = new DfsBlockCacheStats(); - PackExtBlockCacheTable tables = PackExtBlockCacheTable.fromCacheTables( - cacheTableWithStats(/* name= */ "defaultName", packStats), - Map.of(PackExt.PACK, cacheTableWithStats(/* name= */ "packName", - packStats))); + public void getAllBlockCacheStats() { + String defaultTableName = "default table"; + DfsBlockCacheStats defaultStats = new DfsBlockCacheStats( + defaultTableName); + incrementCounter(4, + () -> defaultStats.incrementHit(new TestKey(PackExt.REFTABLE))); + + String packTableName = "pack table"; + DfsBlockCacheStats packStats = new DfsBlockCacheStats(packTableName); + incrementCounter(5, + () -> packStats.incrementHit(new TestKey(PackExt.PACK))); - assertThat(tables.getBlockCacheStats().getName(), - equalTo("defaultName,packName")); + String bitmapTableName = "bitmap table"; + DfsBlockCacheStats bitmapStats = new DfsBlockCacheStats( + bitmapTableName); + incrementCounter(6, () -> bitmapStats + .incrementHit(new TestKey(PackExt.BITMAP_INDEX))); + + DfsBlockCacheTable defaultTable = cacheTableWithStats(defaultStats); + DfsBlockCacheTable packTable = cacheTableWithStats(packStats); + DfsBlockCacheTable bitmapTable = cacheTableWithStats(bitmapStats); + PackExtBlockCacheTable tables = PackExtBlockCacheTable + .fromCacheTables(defaultTable, Map.of(PackExt.PACK, packTable, + PackExt.BITMAP_INDEX, bitmapTable)); + + List<BlockCacheStats> statsList = tables.getBlockCacheStats(); + assertThat(statsList, hasSize(3)); + + long[] defaultTableHitCounts = createEmptyStatsArray(); + defaultTableHitCounts[PackExt.REFTABLE.getPosition()] = 4; + assertArrayEquals( + getCacheStatsByName(statsList, defaultTableName).getHitCount(), + defaultTableHitCounts); + + long[] packTableHitCounts = createEmptyStatsArray(); + packTableHitCounts[PackExt.PACK.getPosition()] = 5; + assertArrayEquals( + getCacheStatsByName(statsList, packTableName).getHitCount(), + packTableHitCounts); + + long[] bitmapHitCounts = createEmptyStatsArray(); + bitmapHitCounts[PackExt.BITMAP_INDEX.getPosition()] = 6; + assertArrayEquals( + getCacheStatsByName(statsList, bitmapTableName).getHitCount(), + bitmapHitCounts); } @Test @@ -431,7 +469,8 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getCurrentSize(), + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getCurrentSize(), currentSizes); } @@ -460,7 +499,9 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getHitCount(), hitCounts); + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getHitCount(), + hitCounts); } @Test @@ -488,7 +529,8 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getMissCount(), + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getMissCount(), missCounts); } @@ -523,8 +565,9 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getTotalRequestCount(), - totalRequestCounts); + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()) + .getTotalRequestCount(), totalRequestCounts); } @Test @@ -554,7 +597,9 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getHitRatio(), hitRatios); + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getHitRatio(), + hitRatios); } @Test @@ -582,10 +627,21 @@ public class PackExtBlockCacheTableTest { cacheTableWithStats(bitmapStats), PackExt.INDEX, cacheTableWithStats(indexStats))); - assertArrayEquals(tables.getBlockCacheStats().getEvictions(), + assertArrayEquals(AggregatedBlockCacheStats + .fromStatsList(tables.getBlockCacheStats()).getEvictions(), evictions); } + private BlockCacheStats getCacheStatsByName( + List<BlockCacheStats> blockCacheStats, String name) { + for (BlockCacheStats entry : blockCacheStats) { + if (entry.getName().equals(name)) { + return entry; + } + } + return null; + } + private static void incrementCounter(int amount, Runnable fn) { for (int i = 0; i < amount; i++) { fn.run(); @@ -597,15 +653,16 @@ public class PackExtBlockCacheTableTest { } private static DfsBlockCacheTable cacheTableWithStats( - DfsBlockCacheStats dfsBlockCacheStats) { + BlockCacheStats dfsBlockCacheStats) { return cacheTableWithStats(CACHE_NAME, dfsBlockCacheStats); } private static DfsBlockCacheTable cacheTableWithStats(String name, - DfsBlockCacheStats dfsBlockCacheStats) { + BlockCacheStats dfsBlockCacheStats) { DfsBlockCacheTable cacheTable = mock(DfsBlockCacheTable.class); when(cacheTable.getName()).thenReturn(name); - when(cacheTable.getBlockCacheStats()).thenReturn(dfsBlockCacheStats); + when(cacheTable.getBlockCacheStats()) + .thenReturn(List.of(dfsBlockCacheStats)); return cacheTable; } diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java index 820f0c768d..42b99ae512 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesAfterBitmapStatisticsTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/GcNumberOfPackFilesSinceBitmapStatisticsTest.java @@ -33,18 +33,18 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.util.FileUtils; import org.junit.Test; -public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase { +public class GcNumberOfPackFilesSinceBitmapStatisticsTest extends GcTestCase { @Test public void testShouldReportZeroObjectsForInitializedRepo() throws IOException { - assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); } @Test public void testShouldReportAllPackFilesWhenNoGcWasPerformed() throws Exception { packAndPrune(); - long result = gc.getStatistics().numberOfPackFilesAfterBitmap; + long result = gc.getStatistics().numberOfPackFilesSinceBitmap; assertEquals(repo.getObjectDatabase().getPacks().size(), result); } @@ -55,11 +55,11 @@ public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase { addCommit(null); gc.gc().get(); assertEquals(1L, repositoryBitmapFiles()); - assertEquals(0L, gc.getStatistics().numberOfPackFilesAfterBitmap); + assertEquals(0L, gc.getStatistics().numberOfPackFilesSinceBitmap); } @Test - public void testShouldReportNewObjectsAfterGcWhenRepositoryProgresses() + public void testShouldReportNewObjectsSinceGcWhenRepositoryProgresses() throws Exception { // commit & gc RevCommit parent = addCommit(null); @@ -70,7 +70,7 @@ public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase { addCommit(parent); packAndPrune(); - assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap); + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); } @Test @@ -90,7 +90,7 @@ public class GcNumberOfPackFilesAfterBitmapStatisticsTest extends GcTestCase { addCommit(parent); packAndPrune(); - assertEquals(1L, gc.getStatistics().numberOfPackFilesAfterBitmap); + assertEquals(1L, gc.getStatistics().numberOfPackFilesSinceBitmap); } private void packAndPrune() throws Exception { diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters index f2c73f5c48..aed6683062 100644 --- a/org.eclipse.jgit/.settings/.api_filters +++ b/org.eclipse.jgit/.settings/.api_filters @@ -36,4 +36,18 @@ </message_arguments> </filter> </resource> + <resource path="src/org/eclipse/jgit/util/SystemReader.java" type="org.eclipse.jgit.util.SystemReader"> + <filter id="336695337"> + <message_arguments> + <message_argument value="org.eclipse.jgit.util.SystemReader"/> + <message_argument value="getTimeZoneAt(Instant)"/> + </message_arguments> + </filter> + <filter id="336695337"> + <message_arguments> + <message_argument value="org.eclipse.jgit.util.SystemReader"/> + <message_argument value="now()"/> + </message_arguments> + </filter> + </resource> </component> diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index b1450ef057..024ca77f21 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -640,8 +640,6 @@ readFileStoreAttributesFailed=Reading FileStore attributes from user config fail readerIsRequired=Reader is required readingObjectsFromLocalRepositoryFailed=reading objects from local repository failed: {0} readLastModifiedFailed=Reading lastModified of {0} failed -readPipeIsNotAllowed=FS.readPipe() isn't allowed for command ''{0}''. Working directory: ''{1}''. -readPipeIsNotAllowedRequiredPermission=FS.readPipe() isn't allowed for command ''{0}''. Working directory: ''{1}''. Required permission: {2}. readTimedOut=Read timed out after {0} ms receivePackObjectTooLarge1=Object too large, rejecting the pack. Max object size limit is {0} bytes. receivePackObjectTooLarge2=Object too large ({0} bytes), rejecting the pack. Max object size limit is {1} bytes. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index 310962b967..0980219e25 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -670,8 +670,6 @@ public class JGitText extends TranslationBundle { /***/ public String readerIsRequired; /***/ public String readingObjectsFromLocalRepositoryFailed; /***/ public String readLastModifiedFailed; - /***/ public String readPipeIsNotAllowed; - /***/ public String readPipeIsNotAllowedRequiredPermission; /***/ public String readTimedOut; /***/ public String receivePackObjectTooLarge1; /***/ public String receivePackObjectTooLarge2; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java index 743f4606c4..295b702fa7 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/AggregatedBlockCacheStats.java @@ -20,27 +20,23 @@ import org.eclipse.jgit.internal.storage.pack.PackExt; * Aggregates values for all given {@link BlockCacheStats}. */ class AggregatedBlockCacheStats implements BlockCacheStats { - private final String name; - private final List<BlockCacheStats> blockCacheStats; - static BlockCacheStats fromStatsList(String name, + static BlockCacheStats fromStatsList( List<BlockCacheStats> blockCacheStats) { if (blockCacheStats.size() == 1) { return blockCacheStats.get(0); } - return new AggregatedBlockCacheStats(name, blockCacheStats); + return new AggregatedBlockCacheStats(blockCacheStats); } - private AggregatedBlockCacheStats(String name, - List<BlockCacheStats> blockCacheStats) { - this.name = name; + private AggregatedBlockCacheStats(List<BlockCacheStats> blockCacheStats) { this.blockCacheStats = blockCacheStats; } @Override public String getName() { - return name; + return AggregatedBlockCacheStats.class.getName(); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java index bbee23b061..587d482583 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/ClockBlockCacheTable.java @@ -12,6 +12,7 @@ package org.eclipse.jgit.internal.storage.dfs; import java.io.IOException; import java.time.Duration; +import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReferenceArray; @@ -141,8 +142,8 @@ final class ClockBlockCacheTable implements DfsBlockCacheTable { } @Override - public BlockCacheStats getBlockCacheStats() { - return dfsBlockCacheStats; + public List<BlockCacheStats> getBlockCacheStats() { + return List.of(dfsBlockCacheStats); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java index 0334450fbe..f8e0831e1f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCache.java @@ -11,7 +11,10 @@ package org.eclipse.jgit.internal.storage.dfs; +import static org.eclipse.jgit.internal.storage.dfs.DfsBlockCacheTable.BlockCacheStats; + import java.io.IOException; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.LongStream; @@ -124,7 +127,7 @@ public final class DfsBlockCache { * @return total number of bytes in the cache, per pack file extension. */ public long[] getCurrentSize() { - return dfsBlockCacheTable.getBlockCacheStats().getCurrentSize(); + return getAggregatedBlockCacheStats().getCurrentSize(); } /** @@ -143,7 +146,7 @@ public final class DfsBlockCache { * extension. */ public long[] getHitCount() { - return dfsBlockCacheTable.getBlockCacheStats().getHitCount(); + return getAggregatedBlockCacheStats().getHitCount(); } /** @@ -154,7 +157,7 @@ public final class DfsBlockCache { * extension. */ public long[] getMissCount() { - return dfsBlockCacheTable.getBlockCacheStats().getMissCount(); + return getAggregatedBlockCacheStats().getMissCount(); } /** @@ -163,7 +166,7 @@ public final class DfsBlockCache { * @return total number of requests (hit + miss), per pack file extension. */ public long[] getTotalRequestCount() { - return dfsBlockCacheTable.getBlockCacheStats().getTotalRequestCount(); + return getAggregatedBlockCacheStats().getTotalRequestCount(); } /** @@ -172,7 +175,7 @@ public final class DfsBlockCache { * @return hit ratios */ public long[] getHitRatio() { - return dfsBlockCacheTable.getBlockCacheStats().getHitRatio(); + return getAggregatedBlockCacheStats().getHitRatio(); } /** @@ -183,7 +186,18 @@ public final class DfsBlockCache { * file extension. */ public long[] getEvictions() { - return dfsBlockCacheTable.getBlockCacheStats().getEvictions(); + return getAggregatedBlockCacheStats().getEvictions(); + } + + /** + * Get the list of {@link BlockCacheStats} for all underlying caches. + * <p> + * Useful in monitoring caches with breakdown. + * + * @return the list of {@link BlockCacheStats} for all underlying caches. + */ + public List<BlockCacheStats> getAllBlockCacheStats() { + return dfsBlockCacheTable.getBlockCacheStats(); } /** @@ -263,6 +277,11 @@ public final class DfsBlockCache { return dfsBlockCacheTable.get(key, position); } + private BlockCacheStats getAggregatedBlockCacheStats() { + return AggregatedBlockCacheStats + .fromStatsList(dfsBlockCacheTable.getBlockCacheStats()); + } + static final class Ref<T> { final DfsStreamKey key; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java index acd7add5a9..d63c208bbb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheConfig.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.function.Consumer; +import java.util.function.Function; import java.util.stream.Collectors; import org.eclipse.jgit.internal.JGitText; @@ -300,12 +301,24 @@ public class DfsBlockCacheConfig { * map of hot count per pack extension for {@code DfsBlockCache}. * @return {@code this} */ + /* + * TODO The cache HotMap configuration should be set as a config option and + * not passed in through a setter. + */ public DfsBlockCacheConfig setCacheHotMap( Map<PackExt, Integer> cacheHotMap) { this.cacheHotMap = Collections.unmodifiableMap(cacheHotMap); + setCacheHotMapToPackExtConfigs(this.cacheHotMap); return this; } + private void setCacheHotMapToPackExtConfigs( + Map<PackExt, Integer> cacheHotMap) { + for (DfsBlockCachePackExtConfig packExtConfig : packExtCacheConfigurations) { + packExtConfig.setCacheHotMap(cacheHotMap); + } + } + /** * Get the consumer of cache index events. * @@ -433,6 +446,7 @@ public class DfsBlockCacheConfig { cacheConfigs.add(cacheConfig); } packExtCacheConfigurations = cacheConfigs; + setCacheHotMapToPackExtConfigs(this.cacheHotMap); } private static <T> Set<T> intersection(Set<T> first, Set<T> second) { @@ -551,6 +565,14 @@ public class DfsBlockCacheConfig { return packExtCacheConfiguration; } + void setCacheHotMap(Map<PackExt, Integer> cacheHotMap) { + Map<PackExt, Integer> packExtHotMap = packExts.stream() + .filter(cacheHotMap::containsKey) + .collect(Collectors.toUnmodifiableMap(Function.identity(), + cacheHotMap::get)); + packExtCacheConfiguration.setCacheHotMap(packExtHotMap); + } + private static DfsBlockCachePackExtConfig fromConfig(Config config, String section, String subSection) { String packExtensions = config.getString(section, subSection, diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java index 43ba8c36ab..c3fd07b7bb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsBlockCacheTable.java @@ -11,6 +11,7 @@ package org.eclipse.jgit.internal.storage.dfs; import java.io.IOException; +import java.util.List; /** * Block cache table. @@ -125,13 +126,17 @@ public interface DfsBlockCacheTable { <T> T get(DfsStreamKey key, long position); /** - * Get the {@link BlockCacheStats} object for this block cache table's - * statistics. + * Get the list of {@link BlockCacheStats} held by this cache. + * <p> + * The returned list has a {@link BlockCacheStats} per configured cache + * table, with a minimum of 1 {@link BlockCacheStats} object returned. + * + * Use {@link AggregatedBlockCacheStats} to combine the results of the stats + * in the list for an aggregated view of the cache's stats. * - * @return the {@link BlockCacheStats} tracking this block cache table's - * statistics. + * @return the list of {@link BlockCacheStats} held by this cache. */ - BlockCacheStats getBlockCacheStats(); + List<BlockCacheStats> getBlockCacheStats(); /** * Get the name of the table. diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java index a177669788..e6068a15ec 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java @@ -18,13 +18,13 @@ import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.RE import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.UNREACHABLE_GARBAGE; import static org.eclipse.jgit.internal.storage.dfs.DfsPackCompactor.configureReftable; import static org.eclipse.jgit.internal.storage.pack.PackExt.COMMIT_GRAPH; -import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import static org.eclipse.jgit.internal.storage.pack.PackWriter.NONE; import java.io.IOException; +import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; @@ -100,6 +100,7 @@ public class DfsGarbageCollector { private Set<ObjectId> allTags; private Set<ObjectId> nonHeads; private Set<ObjectId> tagTargets; + private Instant refLogExpire; /** * Initialize a garbage collector. @@ -200,6 +201,22 @@ public class DfsGarbageCollector { return this; } + + /** + * Set time limit to the reflog history. + * <p> + * Garbage Collector prunes entries from reflog history older than {@code refLogExpire} + * <p> + * + * @param refLogExpire + * instant in time which defines refLog expiration + * @return {@code this} + */ + public DfsGarbageCollector setRefLogExpire(Instant refLogExpire) { + this.refLogExpire = refLogExpire; + return this; + } + /** * Set maxUpdateIndex for the initial reftable created during conversion. * @@ -687,14 +704,7 @@ public class DfsGarbageCollector { pack.setBlockSize(PACK, out.blockSize()); } - try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) { - CountingOutputStream cnt = new CountingOutputStream(out); - pw.writeIndex(cnt); - pack.addFileExt(INDEX); - pack.setFileSize(INDEX, cnt.getCount()); - pack.setBlockSize(INDEX, out.blockSize()); - pack.setIndexVersion(pw.getIndexVersion()); - } + pw.writeIndex(objdb.getPackIndexWriter(pack, pw.getIndexVersion())); if (source != UNREACHABLE_GARBAGE && packConfig.getMinBytesForObjSizeIndex() >= 0) { try (DfsOutputStream out = objdb.writeFile(pack, @@ -741,6 +751,10 @@ public class DfsGarbageCollector { compact.addAll(stack.readers()); compact.setIncludeDeletes(includeDeletes); compact.setConfig(configureReftable(reftableConfig, out)); + if(refLogExpire != null ){ + compact.setReflogExpireOldestReflogTimeMillis( + refLogExpire.toEpochMilli()); + } compact.compact(); pack.addFileExt(REFTABLE); pack.setReftableStats(compact.getStats()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java index 8f09261674..16315bf4f2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java @@ -41,12 +41,13 @@ import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.errors.LargeObjectException; import org.eclipse.jgit.internal.JGitText; -import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; +import org.eclipse.jgit.internal.storage.file.PackIndex; import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.lib.AbbreviatedObjectId; import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectIdOwnerMap; @@ -54,7 +55,6 @@ import org.eclipse.jgit.lib.ObjectInserter; import org.eclipse.jgit.lib.ObjectLoader; import org.eclipse.jgit.lib.ObjectReader; import org.eclipse.jgit.lib.ObjectStream; -import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.transport.PackedObjectInfo; import org.eclipse.jgit.util.BlockList; import org.eclipse.jgit.util.IO; @@ -71,6 +71,8 @@ public class DfsInserter extends ObjectInserter { private static final int INDEX_VERSION = 2; final DfsObjDatabase db; + + private final int minBytesForObjectSizeIndex; int compression = Deflater.BEST_COMPRESSION; List<PackedObjectInfo> objectList; @@ -83,8 +85,6 @@ public class DfsInserter extends ObjectInserter { private boolean rollback; private boolean checkExisting = true; - private int minBytesForObjectSizeIndex = -1; - /** * Initialize a new inserter. * @@ -93,8 +93,9 @@ public class DfsInserter extends ObjectInserter { */ protected DfsInserter(DfsObjDatabase db) { this.db = db; - PackConfig pc = new PackConfig(db.getRepository()); - this.minBytesForObjectSizeIndex = pc.getMinBytesForObjSizeIndex(); + this.minBytesForObjectSizeIndex = db.getRepository().getConfig().getInt( + ConfigConstants.CONFIG_PACK_SECTION, + ConfigConstants.CONFIG_KEY_MIN_BYTES_OBJ_SIZE_INDEX, -1); } /** @@ -112,21 +113,6 @@ public class DfsInserter extends ObjectInserter { void setCompressionLevel(int compression) { this.compression = compression; } - - /** - * Set minimum size for an object to be included in the object size index. - * - * <p> - * Use 0 for all and -1 for nothing (the pack won't have object size index). - * - * @param minBytes - * only objects with size bigger or equal to this are included in - * the index. - */ - protected void setMinBytesForObjectSizeIndex(int minBytes) { - this.minBytesForObjectSizeIndex = minBytes; - } - @Override public DfsPackParser newPackParser(InputStream in) throws IOException { return new DfsPackParser(db, this, in); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java index 616563ffdd..efd666ff27 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsObjDatabase.java @@ -12,6 +12,7 @@ package org.eclipse.jgit.internal.storage.dfs; import static java.util.stream.Collectors.joining; import static org.eclipse.jgit.internal.storage.pack.PackExt.BITMAP_INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; import java.io.FileNotFoundException; import java.io.IOException; @@ -27,7 +28,9 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; +import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; import org.eclipse.jgit.internal.storage.file.PackBitmapIndexWriterV1; +import org.eclipse.jgit.internal.storage.pack.PackIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackBitmapIndexWriter; import org.eclipse.jgit.internal.storage.pack.PackExt; import org.eclipse.jgit.lib.AnyObjectId; @@ -771,4 +774,35 @@ public abstract class DfsObjDatabase extends ObjectDatabase { } }; } + + /** + * Returns a writer to store the pack index in this object database. + * + * @param pack + * Pack file to which the index is associated. + * @param indexVersion + * which version of the index to write + * @return a writer to store the index associated with the pack + * @throws IOException + * when some I/O problem occurs while creating or writing to + * output stream + */ + public PackIndexWriter getPackIndexWriter( + DfsPackDescription pack, int indexVersion) + throws IOException { + return (objectsToStore, packDataChecksum) -> { + try (DfsOutputStream out = writeFile(pack, INDEX); + CountingOutputStream cnt = new CountingOutputStream(out)) { + final PackIndexWriter iw = BasePackIndexWriter + .createVersion(cnt, + indexVersion); + iw.write(objectsToStore, packDataChecksum); + pack.addFileExt(INDEX); + pack.setFileSize(INDEX, cnt.getCount()); + pack.setBlockSize(INDEX, out.blockSize()); + pack.setIndexVersion(indexVersion); + } + }; + } + } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java index 86144b389c..f9c01b9d6e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java @@ -12,7 +12,7 @@ package org.eclipse.jgit.internal.storage.dfs; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.COMPACT; import static org.eclipse.jgit.internal.storage.dfs.DfsObjDatabase.PackSource.GC; -import static org.eclipse.jgit.internal.storage.pack.PackExt.INDEX; +import static org.eclipse.jgit.internal.storage.pack.PackExt.OBJECT_SIZE_INDEX; import static org.eclipse.jgit.internal.storage.pack.PackExt.PACK; import static org.eclipse.jgit.internal.storage.pack.PackExt.REFTABLE; import static org.eclipse.jgit.internal.storage.pack.StoredObjectRepresentation.PACK_DELTA; @@ -249,6 +249,7 @@ public class DfsPackCompactor { try { writePack(objdb, outDesc, pw, pm); writeIndex(objdb, outDesc, pw); + writeObjectSizeIndex(objdb, outDesc, pw); PackStatistics stats = pw.getStatistics(); @@ -458,13 +459,20 @@ public class DfsPackCompactor { private static void writeIndex(DfsObjDatabase objdb, DfsPackDescription pack, PackWriter pw) throws IOException { - try (DfsOutputStream out = objdb.writeFile(pack, INDEX)) { + pw.writeIndex(objdb.getPackIndexWriter(pack, pw.getIndexVersion())); + } + + private static void writeObjectSizeIndex(DfsObjDatabase objdb, + DfsPackDescription pack, + PackWriter pw) throws IOException { + try (DfsOutputStream out = objdb.writeFile(pack, OBJECT_SIZE_INDEX)) { CountingOutputStream cnt = new CountingOutputStream(out); - pw.writeIndex(cnt); - pack.addFileExt(INDEX); - pack.setFileSize(INDEX, cnt.getCount()); - pack.setBlockSize(INDEX, out.blockSize()); - pack.setIndexVersion(pw.getIndexVersion()); + pw.writeObjectSizeIndex(cnt); + if (cnt.getCount() > 0) { + pack.addFileExt(OBJECT_SIZE_INDEX); + pack.setFileSize(OBJECT_SIZE_INDEX, cnt.getCount()); + pack.setBlockSize(OBJECT_SIZE_INDEX, out.blockSize()); + } } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java index e45643be84..28b021c68f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackExtBlockCacheTable.java @@ -188,11 +188,10 @@ class PackExtBlockCacheTable implements DfsBlockCacheTable { } @Override - public BlockCacheStats getBlockCacheStats() { - return AggregatedBlockCacheStats.fromStatsList(name, - blockCacheTableList.stream() - .map(DfsBlockCacheTable::getBlockCacheStats) - .collect(Collectors.toList())); + public List<BlockCacheStats> getBlockCacheStats() { + return blockCacheTableList.stream() + .flatMap(cacheTable -> cacheTable.getBlockCacheStats().stream()) + .collect(Collectors.toList()); } @Override diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java index 34b5ec01e1..3df291f11b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java @@ -1509,10 +1509,10 @@ public class GC { public long numberOfPackFiles; /** - * The number of pack files that were created after the last bitmap + * The number of pack files that were created since the last bitmap * generation. */ - public long numberOfPackFilesAfterBitmap; + public long numberOfPackFilesSinceBitmap; /** * The number of objects stored as loose objects. @@ -1549,8 +1549,8 @@ public class GC { final StringBuilder b = new StringBuilder(); b.append("numberOfPackedObjects=").append(numberOfPackedObjects); //$NON-NLS-1$ b.append(", numberOfPackFiles=").append(numberOfPackFiles); //$NON-NLS-1$ - b.append(", numberOfPackFilesAfterBitmap=") //$NON-NLS-1$ - .append(numberOfPackFilesAfterBitmap); + b.append(", numberOfPackFilesSinceBitmap=") //$NON-NLS-1$ + .append(numberOfPackFilesSinceBitmap); b.append(", numberOfLooseObjects=").append(numberOfLooseObjects); //$NON-NLS-1$ b.append(", numberOfLooseRefs=").append(numberOfLooseRefs); //$NON-NLS-1$ b.append(", numberOfPackedRefs=").append(numberOfPackedRefs); //$NON-NLS-1$ @@ -1575,10 +1575,11 @@ public class GC { ret.numberOfPackedObjects += p.getIndex().getObjectCount(); ret.numberOfPackFiles++; ret.sizeOfPackedObjects += p.getPackFile().length(); - if (p.getBitmapIndex() != null) + if (p.getBitmapIndex() != null) { ret.numberOfBitmaps += p.getBitmapIndex().getBitmapCount(); - else - ret.numberOfPackFilesAfterBitmap++; + } else { + ret.numberOfPackFilesSinceBitmap++; + } } File objDir = repo.getObjectsDirectory(); String[] fanout = objDir.list(); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java index 4fd2eb5798..f025d4e3d5 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java @@ -59,9 +59,9 @@ import org.eclipse.jgit.errors.SearchForReuseTimeout; import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException; import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.storage.file.BasePackIndexWriter; +import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; import org.eclipse.jgit.internal.storage.file.PackObjectSizeIndexWriter; import org.eclipse.jgit.internal.storage.file.PackReverseIndexWriter; -import org.eclipse.jgit.internal.storage.file.PackBitmapIndexBuilder; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.AsyncObjectSizeQueue; import org.eclipse.jgit.lib.BatchingProgressMonitor; @@ -118,7 +118,7 @@ import org.eclipse.jgit.util.TemporaryBuffer; * {@link #preparePack(ProgressMonitor, Set, Set)}, and streaming with * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}. If the * pack is being stored as a file the matching index can be written out after - * writing the pack by {@link #writeIndex(OutputStream)}. An optional bitmap + * writing the pack by {@link #writeIndex(PackIndexWriter)}. An optional bitmap * index can be made by calling {@link #prepareBitmapIndex(ProgressMonitor)} * followed by {@link #writeBitmapIndex(PackBitmapIndexWriter)}. * </p> @@ -1099,12 +1099,28 @@ public class PackWriter implements AutoCloseable { * the index data could not be written to the supplied stream. */ public void writeIndex(OutputStream indexStream) throws IOException { + writeIndex(BasePackIndexWriter.createVersion(indexStream, + getIndexVersion())); + } + + /** + * Create an index file to match the pack file just written. + * <p> + * Called after + * {@link #writePack(ProgressMonitor, ProgressMonitor, OutputStream)}. + * <p> + * Writing an index is only required for local pack storage. Packs sent on + * the network do not need to create an index. + * + * @param iw + * an {@link PackIndexWriter} instance to write the index + * @throws java.io.IOException + * the index data could not be written to the supplied stream. + */ + public void writeIndex(PackIndexWriter iw) throws IOException { if (isIndexDisabled()) throw new IOException(JGitText.get().cachedPacksPreventsIndexCreation); - long writeStart = System.currentTimeMillis(); - PackIndexWriter iw = BasePackIndexWriter.createVersion(indexStream, - getIndexVersion()); iw.write(sortByName(), packcsum); stats.timeWriting += System.currentTimeMillis() - writeStart; } @@ -2448,7 +2464,7 @@ public class PackWriter implements AutoCloseable { * object graph at selected commits. Writing a bitmap index is an optional * feature that not all pack users may require. * <p> - * Called after {@link #writeIndex(OutputStream)}. + * Called after {@link #writeIndex(PackIndexWriter)}. * <p> * To reduce memory internal state is cleared during this method, rendering * the PackWriter instance useless for anything further than a call to write diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java index d232be6276..0c1da83dfb 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BaseRepositoryBuilder.java @@ -15,6 +15,7 @@ import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BARE; import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_WORKTREE; import static org.eclipse.jgit.lib.Constants.CONFIG; import static org.eclipse.jgit.lib.Constants.DOT_GIT; +import static org.eclipse.jgit.lib.Constants.GITDIR_FILE; import static org.eclipse.jgit.lib.Constants.GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY; import static org.eclipse.jgit.lib.Constants.GIT_CEILING_DIRECTORIES_KEY; import static org.eclipse.jgit.lib.Constants.GIT_COMMON_DIR_KEY; @@ -23,7 +24,6 @@ import static org.eclipse.jgit.lib.Constants.GIT_INDEX_FILE_KEY; import static org.eclipse.jgit.lib.Constants.GIT_OBJECT_DIRECTORY_KEY; import static org.eclipse.jgit.lib.Constants.GIT_WORK_TREE_KEY; import static org.eclipse.jgit.lib.Constants.OBJECTS; -import static org.eclipse.jgit.lib.Constants.GITDIR_FILE; import java.io.File; import java.io.IOException; @@ -485,7 +485,7 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re if (getAlternateObjectDirectories() == null) { String val = sr.getenv(GIT_ALTERNATE_OBJECT_DIRECTORIES_KEY); if (val != null) { - for (String path : val.split(File.pathSeparator)) + for (String path : val.split(File.pathSeparator, -1)) addAlternateObjectDirectory(new File(path)); } } @@ -505,7 +505,7 @@ public class BaseRepositoryBuilder<B extends BaseRepositoryBuilder, R extends Re if (ceilingDirectories == null) { String val = sr.getenv(GIT_CEILING_DIRECTORIES_KEY); if (val != null) { - for (String path : val.split(File.pathSeparator)) + for (String path : val.split(File.pathSeparator, -1)) addCeilingDirectory(new File(path)); } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java index 01aa925a86..997f4ed314 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Constants.java @@ -12,8 +12,13 @@ package org.eclipse.jgit.lib; +import static java.nio.charset.StandardCharsets.US_ASCII; import static java.nio.charset.StandardCharsets.UTF_8; +import java.nio.CharBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CodingErrorAction; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.MessageFormat; @@ -721,14 +726,15 @@ public final class Constants { * the 7-bit ASCII character space. */ public static byte[] encodeASCII(String s) { - final byte[] r = new byte[s.length()]; - for (int k = r.length - 1; k >= 0; k--) { - final char c = s.charAt(k); - if (c > 127) - throw new IllegalArgumentException(MessageFormat.format(JGitText.get().notASCIIString, s)); - r[k] = (byte) c; + try { + CharsetEncoder encoder = US_ASCII.newEncoder() + .onUnmappableCharacter(CodingErrorAction.REPORT) + .onMalformedInput(CodingErrorAction.REPORT); + return encoder.encode(CharBuffer.wrap(s)).array(); + } catch (CharacterCodingException e) { + throw new IllegalArgumentException( + MessageFormat.format(JGitText.get().notASCIIString, s), e); } - return r; } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java index 2cf24185c7..114246beb2 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefDatabase.java @@ -160,7 +160,7 @@ public abstract class RefDatabase { if (existing.startsWith(prefix)) conflicting.add(existing); - return conflicting; + return Collections.unmodifiableList(conflicting); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java index a0194ea8b1..8120df0698 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/SshSessionFactory.java @@ -11,8 +11,6 @@ package org.eclipse.jgit.transport; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.Iterator; import java.util.ServiceLoader; @@ -99,9 +97,8 @@ public abstract class SshSessionFactory { * @since 5.2 */ public static String getLocalUserName() { - return AccessController - .doPrivileged((PrivilegedAction<String>) () -> SystemReader - .getInstance().getProperty(Constants.OS_USER_NAME_KEY)); + return SystemReader.getInstance() + .getProperty(Constants.OS_USER_NAME_KEY); } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java index 125ee6cbe9..95b8221a8b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java @@ -36,29 +36,39 @@ import org.eclipse.jgit.annotations.NonNull; */ public interface HttpConnection { /** + * HttpURLConnection#HTTP_OK + * * @see HttpURLConnection#HTTP_OK */ int HTTP_OK = java.net.HttpURLConnection.HTTP_OK; /** + * HttpURLConnection#HTTP_NOT_AUTHORITATIVE + * * @see HttpURLConnection#HTTP_NOT_AUTHORITATIVE * @since 5.8 */ int HTTP_NOT_AUTHORITATIVE = java.net.HttpURLConnection.HTTP_NOT_AUTHORITATIVE; /** + * HttpURLConnection#HTTP_MOVED_PERM + * * @see HttpURLConnection#HTTP_MOVED_PERM * @since 4.7 */ int HTTP_MOVED_PERM = java.net.HttpURLConnection.HTTP_MOVED_PERM; /** + * HttpURLConnection#HTTP_MOVED_TEMP + * * @see HttpURLConnection#HTTP_MOVED_TEMP * @since 4.9 */ int HTTP_MOVED_TEMP = java.net.HttpURLConnection.HTTP_MOVED_TEMP; /** + * HttpURLConnection#HTTP_SEE_OTHER + * * @see HttpURLConnection#HTTP_SEE_OTHER * @since 4.9 */ @@ -85,16 +95,22 @@ public interface HttpConnection { int HTTP_11_MOVED_PERM = 308; /** + * HttpURLConnection#HTTP_NOT_FOUND + * * @see HttpURLConnection#HTTP_NOT_FOUND */ int HTTP_NOT_FOUND = java.net.HttpURLConnection.HTTP_NOT_FOUND; /** + * HttpURLConnection#HTTP_UNAUTHORIZED + * * @see HttpURLConnection#HTTP_UNAUTHORIZED */ int HTTP_UNAUTHORIZED = java.net.HttpURLConnection.HTTP_UNAUTHORIZED; /** + * HttpURLConnection#HTTP_FORBIDDEN + * * @see HttpURLConnection#HTTP_FORBIDDEN */ int HTTP_FORBIDDEN = java.net.HttpURLConnection.HTTP_FORBIDDEN; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java index bcf79a285d..33db6ea661 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/filter/ByteArraySet.java @@ -13,12 +13,12 @@ package org.eclipse.jgit.treewalk.filter; -import org.eclipse.jgit.util.RawParseUtils; - import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; +import org.eclipse.jgit.util.RawParseUtils; + /** * Specialized set for byte arrays, interpreted as strings for use in * {@link PathFilterGroup.Group}. Most methods assume the hash is already know @@ -141,13 +141,19 @@ class ByteArraySet { } /** + * Returns number of arrays in the set + * * @return number of arrays in the set */ int size() { return size; } - /** @return true if {@link #size()} is 0. */ + /** + * Returns true if {@link #size()} is 0 + * + * @return true if {@link #size()} is 0 + */ boolean isEmpty() { return size == 0; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java index 860c1c92fd..59bbacfa76 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java @@ -30,7 +30,6 @@ import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.attribute.BasicFileAttributes; import java.nio.file.attribute.FileTime; -import java.security.AccessControlException; import java.text.MessageFormat; import java.time.Duration; import java.time.Instant; @@ -262,31 +261,6 @@ public abstract class FS { private static final AtomicInteger threadNumber = new AtomicInteger(1); /** - * Don't use the default thread factory of the ForkJoinPool for the - * CompletableFuture; it runs without any privileges, which causes - * trouble if a SecurityManager is present. - * <p> - * Instead use normal daemon threads. They'll belong to the - * SecurityManager's thread group, or use the one of the calling thread, - * as appropriate. - * </p> - * - * @see java.util.concurrent.Executors#newCachedThreadPool() - */ - private static final ExecutorService FUTURE_RUNNER = new ThreadPoolExecutor( - 5, 5, 30L, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), - runnable -> { - Thread t = new Thread(runnable, - "JGit-FileStoreAttributeReader-" //$NON-NLS-1$ - + threadNumber.getAndIncrement()); - // Make sure these threads don't prevent application/JVM - // shutdown. - t.setDaemon(true); - return t; - }); - - /** * Use a separate executor with at most one thread to synchronize * writing to the config. We write asynchronously since the config * itself might be on a different file system, which might otherwise @@ -463,7 +437,7 @@ public abstract class FS { locks.remove(s); } return attributes; - }, FUTURE_RUNNER); + }); f = f.exceptionally(e -> { LOG.error(e.getLocalizedMessage(), e); return Optional.empty(); @@ -1391,13 +1365,6 @@ public abstract class FS { } } catch (IOException e) { LOG.error("Caught exception in FS.readPipe()", e); //$NON-NLS-1$ - } catch (AccessControlException e) { - LOG.warn(MessageFormat.format( - JGitText.get().readPipeIsNotAllowedRequiredPermission, - command, dir, e.getPermission())); - } catch (SecurityException e) { - LOG.warn(MessageFormat.format(JGitText.get().readPipeIsNotAllowed, - command, dir)); } if (debug) { LOG.debug("readpipe returns null"); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java index 635351ac84..237879110a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32_Cygwin.java @@ -14,8 +14,6 @@ import static java.nio.charset.StandardCharsets.UTF_8; import java.io.File; import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -43,10 +41,7 @@ public class FS_Win32_Cygwin extends FS_Win32 { * @return true if cygwin is found */ public static boolean isCygwin() { - final String path = AccessController - .doPrivileged((PrivilegedAction<String>) () -> System - .getProperty("java.library.path") //$NON-NLS-1$ - ); + final String path = System.getProperty("java.library.path"); //$NON-NLS-1$ if (path == null) return false; File found = FS.searchPath(path, "cygpath.exe"); //$NON-NLS-1$ @@ -99,9 +94,7 @@ public class FS_Win32_Cygwin extends FS_Win32 { @Override protected File userHomeImpl() { - final String home = AccessController.doPrivileged( - (PrivilegedAction<String>) () -> System.getenv("HOME") //$NON-NLS-1$ - ); + final String home = System.getenv("HOME"); //$NON-NLS-1$ if (home == null || home.length() == 0) return super.userHomeImpl(); return resolve(new File("."), home); //$NON-NLS-1$ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java index d957deb34c..efa6e7ddc3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/Stats.java @@ -43,14 +43,18 @@ public class Stats { } /** - * @return number of the added values + * Returns the number of added values + * + * @return the number of added values */ public int count() { return n; } /** - * @return minimum of the added values + * Returns the smallest value added + * + * @return the smallest value added */ public double min() { if (n < 1) { @@ -60,7 +64,9 @@ public class Stats { } /** - * @return maximum of the added values + * Returns the biggest value added + * + * @return the biggest value added */ public double max() { if (n < 1) { @@ -70,9 +76,10 @@ public class Stats { } /** - * @return average of the added values + * Returns the average of the added values + * + * @return the average of the added values */ - public double avg() { if (n < 1) { return Double.NaN; @@ -81,7 +88,9 @@ public class Stats { } /** - * @return variance of the added values + * Returns the variance of the added values + * + * @return the variance of the added values */ public double var() { if (n < 2) { @@ -91,7 +100,9 @@ public class Stats { } /** - * @return standard deviation of the added values + * Returns the standard deviation of the added values + * + * @return the standard deviation of the added values */ public double stddev() { return Math.sqrt(this.var()); diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java index ed62c71371..7150e471bc 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java @@ -23,10 +23,11 @@ import java.nio.charset.UnsupportedCharsetException; import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.AccessController; -import java.security.PrivilegedAction; import java.text.DateFormat; import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.Locale; import java.util.TimeZone; import java.util.concurrent.atomic.AtomicReference; @@ -169,9 +170,19 @@ public abstract class SystemReader { } @Override + public Instant now() { + return Instant.now(); + } + + @Override public int getTimezone(long when) { return getTimeZone().getOffset(when) / (60 * 1000); } + + @Override + public ZoneOffset getTimeZoneAt(Instant when) { + return getTimeZoneId().getRules().getOffset(when); + } } /** @@ -230,9 +241,19 @@ public abstract class SystemReader { } @Override + public Instant now() { + return delegate.now(); + } + + @Override public int getTimezone(long when) { return delegate.getTimezone(when); } + + @Override + public ZoneOffset getTimeZoneAt(Instant when) { + return delegate.getTimeZoneAt(when); + } } private static volatile SystemReader INSTANCE = DEFAULT; @@ -503,10 +524,22 @@ public abstract class SystemReader { * Get the current system time * * @return the current system time + * + * @deprecated Use {@link #now()} */ + @Deprecated public abstract long getCurrentTime(); /** + * Get the current system time + * + * @return the current system time + * + * @since 7.1 + */ + public abstract Instant now(); + + /** * Get clock instance preferred by this system. * * @return clock instance preferred by this system. @@ -522,20 +555,46 @@ public abstract class SystemReader { * @param when * a system timestamp * @return the local time zone + * + * @deprecated Use {@link #getTimeZoneAt(Instant)} instead. */ + @Deprecated public abstract int getTimezone(long when); /** + * Get the local time zone offset at "when" time + * + * @param when + * a system timestamp + * @return the local time zone + * @since 7.1 + */ + public abstract ZoneOffset getTimeZoneAt(Instant when); + + /** * Get system time zone, possibly mocked for testing * * @return system time zone, possibly mocked for testing * @since 1.2 + * + * @deprecated Use {@link #getTimeZoneId()} */ + @Deprecated public TimeZone getTimeZone() { return TimeZone.getDefault(); } /** + * Get system time zone, possibly mocked for testing + * + * @return system time zone, possibly mocked for testing + * @since 7.1 + */ + public ZoneId getTimeZoneId() { + return ZoneId.systemDefault(); + } + + /** * Get the locale to use * * @return the locale to use @@ -670,9 +729,7 @@ public abstract class SystemReader { } private String getOsName() { - return AccessController.doPrivileged( - (PrivilegedAction<String>) () -> getProperty("os.name") //$NON-NLS-1$ - ); + return getProperty("os.name"); //$NON-NLS-1$ } /** diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java index 4764676c88..13982b133c 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/ThrowingPrintWriter.java @@ -11,8 +11,6 @@ package org.eclipse.jgit.util.io; import java.io.IOException; import java.io.Writer; -import java.security.AccessController; -import java.security.PrivilegedAction; import org.eclipse.jgit.util.SystemReader; @@ -35,10 +33,7 @@ public class ThrowingPrintWriter extends Writer { */ public ThrowingPrintWriter(Writer out) { this.out = out; - LF = AccessController - .doPrivileged((PrivilegedAction<String>) () -> SystemReader - .getInstance().getProperty("line.separator") //$NON-NLS-1$ - ); + LF = SystemReader.getInstance().getProperty("line.separator"); //$NON-NLS-1$ } @Override @@ -137,7 +137,7 @@ <slf4j-version>1.7.36</slf4j-version> <maven-javadoc-plugin-version>3.6.3</maven-javadoc-plugin-version> <gson-version>2.11.0</gson-version> - <bouncycastle-version>1.78.1</bouncycastle-version> + <bouncycastle-version>1.79</bouncycastle-version> <spotbugs-maven-plugin-version>4.8.5.0</spotbugs-maven-plugin-version> <maven-project-info-reports-plugin-version>3.5.1</maven-project-info-reports-plugin-version> <maven-jxr-plugin-version>3.3.2</maven-jxr-plugin-version> @@ -148,7 +148,7 @@ <hamcrest-version>2.2</hamcrest-version> <assertj-version>3.26.3</assertj-version> <jna-version>5.15.0</jna-version> - <byte-buddy-version>1.15.3</byte-buddy-version> + <byte-buddy-version>1.15.10</byte-buddy-version> <!-- Properties to enable jacoco code coverage analysis --> <sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin> @@ -1007,7 +1007,7 @@ <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> - <version>5.14.1</version> + <version>5.14.2</version> </dependency> <dependency> diff --git a/tools/BUILD b/tools/BUILD index 8c424b357b..844f0049e6 100644 --- a/tools/BUILD +++ b/tools/BUILD @@ -10,6 +10,7 @@ default_java_toolchain( java_runtime = "@rules_java//toolchains:remotejdk_17", package_configuration = [ ":error_prone", + ":error_prone_tests", ], source_version = "17", target_version = "17", @@ -22,6 +23,7 @@ default_java_toolchain( java_runtime = "@rules_java//toolchains:remotejdk_21", package_configuration = [ ":error_prone", + ":error_prone_tests", ], source_version = "21", target_version = "21", @@ -32,9 +34,7 @@ default_java_toolchain( # enabled. This warnings list is originally based on: # https://github.com/bazelbuild/BUILD_file_generator/blob/master/tools/bazel_defs/java.bzl # However, feel free to add any additional errors. Thus far they have all been pretty useful. -java_package_configuration( - name = "error_prone", - javacopts = [ +errorprone_checks = [ "-XepDisableWarningsInGeneratedCode", # The XepDisableWarningsInGeneratedCode disables only warnings, but # not errors. We should manually exclude all files generated by @@ -422,37 +422,57 @@ java_package_configuration( "-Xep:WrongOneof:ERROR", "-Xep:XorPower:ERROR", "-Xep:ZoneIdOfZ:ERROR", - ], +] + + +exclude_in_tests = ["-Xep:EmptyBlockTag:WARN", + "-Xep:MissingSummary:WARN"] + +java_package_configuration( + name = "error_prone", + javacopts = errorprone_checks, packages = ["error_prone_packages"], ) +java_package_configuration( + name = "error_prone_tests", + javacopts = [ check for check in errorprone_checks if check not in exclude_in_tests], + packages = ["error_prone_packages_test"], +) + package_group( name = "error_prone_packages", packages = [ - "//org.eclipse.jgit.ant.test/...", "//org.eclipse.jgit.ant/...", "//org.eclipse.jgit.archive/...", - "//org.eclipse.jgit.gpg.bc.test/...", "//org.eclipse.jgit.gpg.bc/...", "//org.eclipse.jgit.http.apache/...", "//org.eclipse.jgit.http.server/...", - "//org.eclipse.jgit.http.test/...", "//org.eclipse.jgit.junit.ssh/...", "//org.eclipse.jgit.junit/...", "//org.eclipse.jgit.junit/http/...", - "//org.eclipse.jgit.lfs.server.test/...", "//org.eclipse.jgit.lfs.server/...", - "//org.eclipse.jgit.lfs.test/...", "//org.eclipse.jgit.lfs/...", - "//org.eclipse.jgit.pgm.test/...", "//org.eclipse.jgit.pgm/...", "//org.eclipse.jgit.ssh.apache.agent/...", - "//org.eclipse.jgit.ssh.apache.test/...", "//org.eclipse.jgit.ssh.apache/...", - "//org.eclipse.jgit.ssh.jsch.test/...", "//org.eclipse.jgit.ssh.jsch/...", - "//org.eclipse.jgit.test/...", "//org.eclipse.jgit.ui/...", "//org.eclipse.jgit/...", ], ) + +package_group( + name = "error_prone_packages_test", + packages = [ + "//org.eclipse.jgit.ant.test/...", + "//org.eclipse.jgit.gpg.bc.test/...", + "//org.eclipse.jgit.http.test/...", + "//org.eclipse.jgit.lfs.server.test/...", + "//org.eclipse.jgit.lfs.test/...", + "//org.eclipse.jgit.pgm.test/...", + "//org.eclipse.jgit.ssh.apache.test/...", + "//org.eclipse.jgit.ssh.jsch.test/...", + "//org.eclipse.jgit.test/...", + ], +) |