Merge "ReftableCompactor should accept 0 for minUpdateIndex"
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
index b78ee04..7b0e7ab 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/CleanFilter.java
@@ -124,7 +124,7 @@ public final static void register() {
 	public CleanFilter(Repository db, InputStream in, OutputStream out)
 			throws IOException {
 		super(in, out);
-		lfsUtil = new Lfs(db.getDirectory().toPath().resolve("lfs")); //$NON-NLS-1$
+		lfsUtil = new Lfs(FileUtils.toPath(db.getDirectory()).resolve("lfs")); //$NON-NLS-1$
 		Files.createDirectories(lfsUtil.getLfsTmpDir());
 		tmpFile = lfsUtil.createTmpFile();
 		this.aOut = new AtomicObjectOutputStream(tmpFile.toAbsolutePath());
diff --git a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
index 2332477..6b1f68d 100644
--- a/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
+++ b/org.eclipse.jgit.lfs/src/org/eclipse/jgit/lfs/SmudgeFilter.java
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.attributes.FilterCommandRegistry;
 import org.eclipse.jgit.lfs.lib.Constants;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.util.FileUtils;
 
 /**
  * Built-in LFS smudge filter
@@ -100,7 +101,7 @@ public final static void register() {
 	public SmudgeFilter(Repository db, InputStream in, OutputStream out)
 			throws IOException {
 		super(in, out);
-		lfs = new Lfs(db.getDirectory().toPath().resolve(Constants.LFS));
+		lfs = new Lfs(FileUtils.toPath(db.getDirectory()).resolve(Constants.LFS));
 		LfsPointer res = LfsPointer.parseLfsPointer(in);
 		if (res != null) {
 			Path mediaFile = lfs.getMediaFile(res.getOid());
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
index db5f1b2..e5a80ae 100644
--- a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/ignore/CGitVsJGitRandomIgnorePatternTest.java
@@ -56,6 +56,7 @@
 import java.util.Random;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.util.FileUtils;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -156,7 +157,7 @@ public CGitIgnoreRule(File gitDir, String pattern)
 				throws UnsupportedEncodingException, IOException {
 			this.gitDir = gitDir;
 			this.pattern = pattern;
-			Files.write(new File(gitDir, ".gitignore").toPath(),
+			Files.write(FileUtils.toPath(new File(gitDir, ".gitignore")),
 					(pattern + "\n").getBytes("UTF-8"),
 					StandardOpenOption.CREATE,
 					StandardOpenOption.TRUNCATE_EXISTING,
diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters
index 20d08c3..595bb4c 100644
--- a/org.eclipse.jgit/.settings/.api_filters
+++ b/org.eclipse.jgit/.settings/.api_filters
@@ -38,6 +38,13 @@
         <filter id="1141899266">
             <message_arguments>
                 <message_argument value="3.5"/>
+                <message_argument value="4.10"/>
+                <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
+            </message_arguments>
+        </filter>
+        <filter id="1141899266">
+            <message_arguments>
+                <message_argument value="3.5"/>
                 <message_argument value="4.9"/>
                 <message_argument value="processEntry(CanonicalTreeParser, CanonicalTreeParser, CanonicalTreeParser, DirCacheBuildIterator, WorkingTreeIterator, boolean)"/>
             </message_arguments>
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 f992a33..3ac643d 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
@@ -950,7 +950,7 @@ private void deleteOrphans() {
 			} else {
 				if (base == null || !n.startsWith(base)) {
 					try {
-						Files.delete(new File(packDir.toFile(), n).toPath());
+						Files.delete(FileUtils.toPath(new File(packDir.toFile(), n)));
 					} catch (IOException e) {
 						LOG.error(e.getMessage(), e);
 					}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
index 994a432..bca7076 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GcLog.java
@@ -58,6 +58,7 @@
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.ConfigConstants;
+import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.GitDateParser;
 import org.eclipse.jgit.util.SystemReader;
 
@@ -105,12 +106,12 @@ private Instant getLogExpiry() throws ParseException {
 
 	private boolean autoGcBlockedByOldLockFile(boolean background) {
 		try {
-			FileTime lastModified = Files.getLastModifiedTime(logFile.toPath());
+			FileTime lastModified = Files.getLastModifiedTime(FileUtils.toPath(logFile));
 			if (lastModified.toInstant().compareTo(getLogExpiry()) > 0) {
 				// There is an existing log file, which is too recent to ignore
 				if (!background) {
 					try (BufferedReader reader = Files
-							.newBufferedReader(logFile.toPath())) {
+							.newBufferedReader(FileUtils.toPath(logFile))) {
 						char[] buf = new char[1000];
 						int len = reader.read(buf, 0, 1000);
 						String oldError = new String(buf, 0, len);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
index 153c7dd..1f1d92e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectory.java
@@ -715,7 +715,7 @@ InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id,
 			return InsertLooseObjectResult.EXISTS_LOOSE;
 		}
 		try {
-			Files.move(tmp.toPath(), dst.toPath(),
+			Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
 					StandardCopyOption.ATOMIC_MOVE);
 			dst.setReadOnly();
 			unpackedObjectCache.add(id);
@@ -732,7 +732,7 @@ InsertLooseObjectResult insertUnpackedObject(File tmp, ObjectId id,
 		//
 		FileUtils.mkdir(dst.getParentFile(), true);
 		try {
-			Files.move(tmp.toPath(), dst.toPath(),
+			Files.move(FileUtils.toPath(tmp), FileUtils.toPath(dst),
 					StandardCopyOption.ATOMIC_MOVE);
 			dst.setReadOnly();
 			unpackedObjectCache.add(id);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index 2d58a02..d456870 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -191,7 +191,7 @@ public boolean setExecute(File f, boolean canExecute) {
 			return f.setExecutable(false, false);
 
 		try {
-			Path path = f.toPath();
+			Path path = FileUtils.toPath(f);
 			Set<PosixFilePermission> pset = Files.getPosixFilePermissions(path);
 
 			// owner (user) is always allowed to execute.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
index 76dbb87..e034be0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FileUtils.java
@@ -51,6 +51,7 @@
 import java.nio.file.AtomicMoveNotSupportedException;
 import java.nio.file.CopyOption;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.LinkOption;
 import java.nio.file.Path;
 import java.nio.file.StandardCopyOption;
@@ -112,6 +113,25 @@ public class FileUtils {
 	public static final int EMPTY_DIRECTORIES_ONLY = 16;
 
 	/**
+	 * Safe conversion from {@link java.io.File} to {@link java.nio.file.Path}.
+	 *
+	 * @param f
+	 *            {@code File} to be converted to {@code Path}
+	 * @throws IOException
+	 *            in case the path represented by the file
+	 *            is not valid ({@link java.nio.file.InvalidPathException})
+	 *
+	 * @since 4.10
+	 */
+	public static Path toPath(final File f) throws IOException {
+		try {
+			return f.toPath();
+		} catch (InvalidPathException ex) {
+			throw new IOException(ex);
+		}
+	}
+
+	/**
 	 * Delete file or empty folder
 	 *
 	 * @param f
@@ -259,7 +279,7 @@ public static void rename(final File src, final File dst,
 		int attempts = FS.DETECTED.retryFailedLockFileCommit() ? 10 : 1;
 		while (--attempts >= 0) {
 			try {
-				Files.move(src.toPath(), dst.toPath(), options);
+				Files.move(toPath(src), toPath(dst), options);
 				return;
 			} catch (AtomicMoveNotSupportedException e) {
 				throw e;
@@ -269,7 +289,7 @@ public static void rename(final File src, final File dst,
 						delete(dst, EMPTY_DIRECTORIES_ONLY | RECURSIVE);
 					}
 					// On *nix there is no try, you do or do not
-					Files.move(src.toPath(), dst.toPath(), options);
+					Files.move(toPath(src), toPath(dst), options);
 					return;
 				} catch (IOException e2) {
 					// ignore and continue retry
@@ -408,7 +428,7 @@ public static void createNewFile(File f) throws IOException {
 	 */
 	public static Path createSymLink(File path, String target)
 			throws IOException {
-		Path nioPath = path.toPath();
+		Path nioPath = toPath(path);
 		if (Files.exists(nioPath, LinkOption.NOFOLLOW_LINKS)) {
 			BasicFileAttributes attrs = Files.readAttributes(nioPath,
 					BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
@@ -421,7 +441,7 @@ public static Path createSymLink(File path, String target)
 		if (SystemReader.getInstance().isWindows()) {
 			target = target.replace('/', '\\');
 		}
-		Path nioTarget = new File(target).toPath();
+		Path nioTarget = toPath(new File(target));
 		return Files.createSymbolicLink(nioPath, nioTarget);
 	}
 
@@ -432,7 +452,7 @@ public static Path createSymLink(File path, String target)
 	 * @since 3.0
 	 */
 	public static String readSymLink(File path) throws IOException {
-		Path nioPath = path.toPath();
+		Path nioPath = toPath(path);
 		Path target = Files.readSymbolicLink(nioPath);
 		String targetString = target.toString();
 		if (SystemReader.getInstance().isWindows()) {
@@ -644,7 +664,7 @@ static boolean isSymlink(File file) {
 	 * @throws IOException
 	 */
 	static long lastModified(File file) throws IOException {
-		return Files.getLastModifiedTime(file.toPath(), LinkOption.NOFOLLOW_LINKS)
+		return Files.getLastModifiedTime(toPath(file), LinkOption.NOFOLLOW_LINKS)
 				.toMillis();
 	}
 
@@ -654,7 +674,7 @@ static long lastModified(File file) throws IOException {
 	 * @throws IOException
 	 */
 	static void setLastModified(File file, long time) throws IOException {
-		Files.setLastModifiedTime(file.toPath(), FileTime.fromMillis(time));
+		Files.setLastModifiedTime(toPath(file), FileTime.fromMillis(time));
 	}
 
 	/**
@@ -672,7 +692,7 @@ static boolean exists(File file) {
 	 * @throws IOException
 	 */
 	static boolean isHidden(File file) throws IOException {
-		return Files.isHidden(file.toPath());
+		return Files.isHidden(toPath(file));
 	}
 
 	/**
@@ -682,7 +702,7 @@ static boolean isHidden(File file) throws IOException {
 	 * @since 4.1
 	 */
 	public static void setHidden(File file, boolean hidden) throws IOException {
-		Files.setAttribute(file.toPath(), "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
+		Files.setAttribute(toPath(file), "dos:hidden", Boolean.valueOf(hidden), //$NON-NLS-1$
 				LinkOption.NOFOLLOW_LINKS);
 	}
 
@@ -693,7 +713,7 @@ public static void setHidden(File file, boolean hidden) throws IOException {
 	 * @since 4.1
 	 */
 	public static long getLength(File file) throws IOException {
-		Path nioPath = file.toPath();
+		Path nioPath = toPath(file);
 		if (Files.isSymbolicLink(nioPath))
 			return Files.readSymbolicLink(nioPath).toString()
 					.getBytes(Constants.CHARSET).length;
@@ -737,7 +757,7 @@ public static boolean canExecute(File file) {
 	 */
 	static Attributes getFileAttributesBasic(FS fs, File file) {
 		try {
-			Path nioPath = file.toPath();
+			Path nioPath = toPath(file);
 			BasicFileAttributes readAttributes = nioPath
 					.getFileSystem()
 					.provider()
@@ -769,7 +789,7 @@ static Attributes getFileAttributesBasic(FS fs, File file) {
 	 */
 	public static Attributes getFileAttributesPosix(FS fs, File file) {
 		try {
-			Path nioPath = file.toPath();
+			Path nioPath = toPath(file);
 			PosixFileAttributes readAttributes = nioPath
 					.getFileSystem()
 					.provider()