Bug 508858: Pass a blocking InputStream to the TarArchiveInputStream.

The input stream returned from copyContainer may be passing back
available bytes which may not default to be 0.  In this case, the
tar input stream may be reading a header record and treat this
incomplete record as EOF.  Also fixed buffering to only write out
what was read (number of bytes).

Change-Id: Icbab8dc460eb613acf6e12cd2f5aba192c52e774
Reviewed-on: https://git.eclipse.org/r/86667
Tested-by: Hudson CI
Reviewed-by: Jeff Johnston <jjohnstn@redhat.com>
diff --git a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CopyFromContainerCommandHandler.java b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CopyFromContainerCommandHandler.java
index 9a28890..a6ad080 100644
--- a/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CopyFromContainerCommandHandler.java
+++ b/containers/org.eclipse.linuxtools.docker.ui/src/org/eclipse/linuxtools/internal/docker/ui/commands/CopyFromContainerCommandHandler.java
@@ -13,6 +13,7 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.util.List;
 
 import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
@@ -109,10 +110,17 @@
 											COPY_FROM_CONTAINER_JOB_SUBTASK,
 											proxy.getFullPath()));
 							monitor.worked(1);
+							InputStream in = ((DockerConnection) connection)
+									.copyContainer(container.id(),
+											proxy.getLink());
+							/*
+							 * The input stream from copyContainer might be
+							 * incomplete or non-blocking so we should wrap it
+							 * in a stream that is guaranteed to block until
+							 * data is available.
+							 */
 							TarArchiveInputStream k = new TarArchiveInputStream(
-									((DockerConnection) connection)
-											.copyContainer(container.id(),
-													proxy.getLink()));
+									new BlockingInputStream(in));
 							TarArchiveEntry te = null;
 							while ((te = k.getNextTarEntry()) != null) {
 								long size = te.getSize();
@@ -126,17 +134,19 @@
 									f.createNewFile();
 								}
 								FileOutputStream os = new FileOutputStream(f);
-								if (size > 4096)
-									size = 4096;
-								byte[] barray = new byte[(int) size];
-								while (k.read(barray) > -1) {
+								int bufferSize = ((int) size > 4096 ? 4096
+										: (int) size);
+								byte[] barray = new byte[bufferSize];
+								int result = -1;
+								while ((result = k.read(barray, 0,
+										bufferSize)) > -1) {
 									if (monitor.isCanceled()) {
 										monitor.done();
 										k.close();
 										os.close();
 										return Status.CANCEL_STATUS;
 									}
-									os.write(barray);
+									os.write(barray, 0, result);
 								}
 								os.close();
 							}
@@ -172,4 +182,20 @@
 
 	}
 
+	/**
+	 * A blocking input stream that waits until data is available.
+	 */
+	public class BlockingInputStream extends InputStream {
+		private InputStream in;
+
+		public BlockingInputStream(InputStream in) {
+			this.in = in;
+		}
+
+		@Override
+		public int read() throws IOException {
+			return in.read();
+		}
+	}
+
 }