Merge branch 'stable-5.2' into stable-5.3

* stable-5.2:
  Use FileSnapshot without using configs for FileBasedConfig

Change-Id: Ib79c310c5b632e845ba69ce65e739ae0146103ca
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
index 5100d25..8b9869a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
@@ -46,6 +46,7 @@
 import static org.eclipse.jgit.util.FileUtils.pathToString;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -54,6 +55,8 @@
 import java.nio.file.Path;
 import java.nio.file.StandardOpenOption;
 import java.util.StringTokenizer;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.junit.MockSystemReader;
@@ -90,11 +93,13 @@
 
 	private Path trash;
 
+	private MockSystemReader mockSystemReader;
+
 	@Before
 	public void setUp() throws Exception {
-		SystemReader.setInstance(new MockSystemReader());
+		mockSystemReader = new MockSystemReader();
+		SystemReader.setInstance(mockSystemReader);
 		trash = Files.createTempDirectory("tmp_");
-		FS.getFileStoreAttributes(trash.getParent());
 	}
 
 	@After
@@ -298,6 +303,37 @@
 		assertEquals(ALICE_EMAIL, config.getString(USER, null, EMAIL));
 	}
 
+	@Test
+	public void testSavedConfigFileShouldNotReadUserGitConfig()
+			throws IOException {
+		AtomicBoolean userConfigTimeRead = new AtomicBoolean(false);
+
+		Path userConfigFile = createFile(CONTENT1.getBytes(), "home");
+		mockSystemReader.setUserGitConfig(
+				new FileBasedConfig(userConfigFile.toFile(), FS.DETECTED) {
+
+					@Override
+					public long getTimeUnit(String section, String subsection,
+							String name, long defaultValue, TimeUnit wantUnit) {
+						userConfigTimeRead.set(true);
+						return super.getTimeUnit(section, subsection, name,
+								defaultValue, wantUnit);
+					}
+				});
+
+		Path file = createFile(CONTENT2.getBytes(), "repo");
+		FileBasedConfig fileBasedConfig = new FileBasedConfig(file.toFile(),
+				FS.DETECTED);
+		fileBasedConfig.save();
+
+		// Needed to trigger the read of FileSnapshot filesystem settings
+		fileBasedConfig.isOutdated();
+		assertFalse(
+				"User config should not be read when accessing config files "
+						+ "for avoiding deadlocks",
+				userConfigTimeRead.get());
+	}
+
 	private Path createFile(byte[] content) throws IOException {
 		return createFile(content, null);
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
index f7e78b9..548ea5a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/LockFile.java
@@ -137,6 +137,8 @@
 
 	private boolean needSnapshot;
 
+	private boolean snapshotNoConfig;
+
 	boolean fsync;
 
 	private FileSnapshot commitSnapshot;
@@ -407,6 +409,21 @@
 	}
 
 	/**
+	 * Request that {@link #commit()} remember the
+	 * {@link org.eclipse.jgit.internal.storage.file.FileSnapshot} without using
+	 * config file to get filesystem timestamp resolution.
+	 * This method should be invoked before the file is accessed.
+	 * It is used by FileBasedConfig to avoid endless recursion.
+	 *
+	 * @param on
+	 *            true if the commit method must remember the FileSnapshot.
+	 */
+	public void setNeedSnapshotNoConfig(boolean on) {
+		needSnapshot = on;
+		snapshotNoConfig = on;
+	}
+
+	/**
 	 * Request that {@link #commit()} force dirty data to the drive.
 	 *
 	 * @param on
@@ -482,8 +499,12 @@
 	}
 
 	private void saveStatInformation() {
-		if (needSnapshot)
-			commitSnapshot = FileSnapshot.save(lck);
+		if (needSnapshot) {
+			commitSnapshot = snapshotNoConfig ?
+				// don't use config in this snapshot to avoid endless recursion
+				FileSnapshot.saveNoConfig(lck)
+				: FileSnapshot.save(lck);
+		}
 	}
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index bdbd7c9..072938b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -235,7 +235,7 @@
 		if (!lf.lock())
 			throw new LockFailedException(getFile());
 		try {
-			lf.setNeedSnapshot(true);
+			lf.setNeedSnapshotNoConfig(true);
 			lf.write(out);
 			if (!lf.commit())
 				throw new IOException(MessageFormat.format(JGitText.get().cannotCommitWriteTo, getFile()));