Check for packfile validity and fd before reading

When reading from a packfile, make sure that is valid
and has a non-null file-descriptor.

Because of concurrency between a thread invalidating a packfile
and another trying to read it, the read() may result into a NPE
that won't be able to be automatically recovered.

Throwing a PackInvalidException would instead cause the packlist
to be refreshed and the read to eventually succeed.

Bug: 544199
Change-Id: I27788b3db759d93ec3212de35c0094ecaafc2434
Signed-off-by: Luca Milanesio <luca.milanesio@gmail.com>
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index cbf7452..7a51a5a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -702,6 +702,14 @@
 
 	ByteArrayWindow read(final long pos, int size) throws IOException {
 		synchronized (readLock) {
+			if (invalid || fd == null) {
+				// Due to concurrency between a read and another packfile invalidation thread
+				// one thread could come up to this point and then fail with NPE.
+				// Detect the situation and throw a proper exception so that can be properly
+				// managed by the main packfile search loop and the Git client won't receive
+				// any failures.
+				throw new PackInvalidException(packFile);
+			}
 			if (length < pos + size)
 				size = (int) (length - pos);
 			final byte[] buf = new byte[size];