Merge branch 'stable-5.12'

* stable-5.12:
  LockFile: create OutputStream only when needed
  Remove ReftableNumbersNotIncreasingException

Change-Id: I9d85187d00771beef908f1136015d059024f4118
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/file/CGitLockFileTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/file/CGitLockFileTest.java
new file mode 100644
index 0000000..4c19475
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/internal/storage/file/CGitLockFileTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2021 SAP SE 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.internal.storage.file;
+
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.junit.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FS.ExecutionResult;
+import org.junit.Test;
+
+/**
+ * Unit tests of {@link LockFile} testing interoperability with C git
+ */
+public class CGitLockFileTest extends RepositoryTestCase {
+
+	@Test
+	public void testLockedTwiceFails() throws Exception {
+		try (Git git = new Git(db)) {
+			writeTrashFile("file.txt", "content");
+			git.add().addFilepattern("file.txt").call();
+			RevCommit commit1 = git.commit().setMessage("create file").call();
+
+			assertNotNull(commit1);
+			writeTrashFile("file.txt", "content2");
+			git.add().addFilepattern("file.txt").call();
+			assertNotNull(git.commit().setMessage("edit file").call());
+
+			LockFile lf = new LockFile(db.getIndexFile());
+			assertTrue(lf.lock());
+			try {
+				String[] command = new String[] { "git", "checkout",
+						commit1.name() };
+				ProcessBuilder pb = new ProcessBuilder(command);
+				pb.directory(db.getWorkTree());
+				ExecutionResult result = FS.DETECTED.execute(pb, null);
+				assertNotEquals(0, result.getRc());
+				String err = result.getStderr().toString().split("\\R")[0];
+				assertTrue(err.matches(
+						"fatal: Unable to create .*/\\.git/index\\.lock': File exists\\."));
+			} finally {
+				lf.unlock();
+			}
+		}
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index 671475e..c904a78 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -1610,11 +1610,9 @@
 		}
 		if (rc != 0) {
 			throw new IOException(new FilterFailedException(rc,
-					checkoutMetadata.smudgeFilterCommand,
-					path,
+					checkoutMetadata.smudgeFilterCommand, path,
 					result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
-					RawParseUtils.decode(result.getStderr()
-							.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
+					result.getStderr().toString(MAX_EXCEPTION_TEXT_SIZE)));
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 55b7d62..0b7c0a9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -502,8 +502,7 @@
 				throw new IOException(new FilterFailedException(rc,
 						filterCommand, getEntryPathString(),
 						result.getStdout().toByteArray(MAX_EXCEPTION_TEXT_SIZE),
-						RawParseUtils.decode(result.getStderr()
-								.toByteArray(MAX_EXCEPTION_TEXT_SIZE))));
+						result.getStderr().toString(MAX_EXCEPTION_TEXT_SIZE)));
 			}
 			return result.getStdout().openInputStreamWithAutoDestroy();
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
index 562eb05..fb893a6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/TemporaryBuffer.java
@@ -18,6 +18,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.UncheckedIOException;
 import java.util.ArrayList;
 
 import org.eclipse.jgit.internal.JGitText;
@@ -213,6 +214,24 @@
 	}
 
 	/**
+	 * Convert first {@code limit} number of bytes of the buffer content to
+	 * String.
+	 *
+	 * @param limit
+	 *            the maximum number of bytes to be converted to String
+	 * @return first {@code limit} number of bytes of the buffer content
+	 *         converted to String.
+	 * @since 5.12
+	 */
+	public String toString(int limit) {
+		try {
+			return RawParseUtils.decode(toByteArray(limit));
+		} catch (IOException e) {
+			throw new UncheckedIOException(e);
+		}
+	}
+
+	/**
 	 * Convert this buffer's contents into a contiguous byte array. If this size
 	 * of the buffer exceeds the limit only return the first {@code limit} bytes
 	 * <p>