Index: TarBuffer.java
===================================================================
--- TarBuffer.java	(revision 1501621)
+++ TarBuffer.java	(working copy)
@@ -49,11 +49,11 @@
     // TODO make these final? (would need to change close() method)
     private InputStream     inStream;
     private OutputStream    outStream;
-    private final int             blockSize;
-    private final int             recordSize;
-    private final int             recsPerBlock;
-    private final byte[]          blockBuffer;
-    private final byte[]          eofRecord;
+    private final int       blockSize;
+    private final int       recordSize;
+    private final int       recsPerBlock;
+    private final byte[]    blockBuffer;
+    private final byte[]    eofRecord;
 
     private int             currBlkIdx;
     private int             currRecIdx;
@@ -126,7 +126,10 @@
             ? DEFAULT_EOF_RECORD : new byte[recordSize];
 
         if (this.inStream != null) {
+        	// on first read, index set to zero
             this.currBlkIdx = -1;
+            
+         // on first read, index set to zero
             this.currRecIdx = this.recsPerBlock;
         } else {
             this.currBlkIdx = 0;
@@ -171,12 +174,45 @@
         }
 
         if (currRecIdx >= recsPerBlock && !readBlock()) {
-            return;    // UNDONE
+            return;
         }
 
         currRecIdx++;
     }
+    
+	/**
+	 * Skip n number of blocks.
+	 * 
+	 * @param numBlocks
+	 *            Number of blocks to skip
+	 * @throws IOException
+	 *             on stream error
+	 */
+    public void skipBlocks(long numBlocks) throws IOException {
+        if (inStream == null) {
+        	throw new IOException("input buffer is closed");
+        }
+        if (this.currBlkIdx < 0)
+        {
+        	this.currBlkIdx = 0;
+        }
 
+        if (numBlocks > 0)
+        {
+        	int oldRecIdx = currRecIdx;
+        	long numBlockSkipped = numBlocks - 1;
+
+        	inStream.skip(numBlockSkipped * (long)blockSize);
+        	currBlkIdx += numBlockSkipped;
+        	
+        	// reset the block buffer
+        	readBlock();
+        	
+        	// readBlock deletes old count
+        	currRecIdx = oldRecIdx;
+        }
+    }
+
     /**
      * Read a record from the input stream and return the data.
      *
@@ -185,10 +221,7 @@
      */
     public byte[] readRecord() throws IOException {
         if (inStream == null) {
-            if (outStream == null) {
-                throw new IOException("input buffer is closed");
-            }
-            throw new IOException("reading from an output buffer");
+        	throw new IOException("input buffer is closed");
         }
 
         if (currRecIdx >= recsPerBlock && !readBlock()) {
@@ -207,62 +240,56 @@
     }
 
     /**
+     * inStream cannot be null
+     *
      * @return false if End-Of-File, else true
      */
-    private boolean readBlock() throws IOException {
-        if (inStream == null) {
-            throw new IOException("reading from an output buffer");
-        }
-
-        currRecIdx = 0;
-
+    private boolean readBlock() throws IOException
+    {
         int offset = 0;
         int bytesNeeded = blockSize;
+        
+        long numBytes = inStream.read(blockBuffer, offset, bytesNeeded);
+        while (numBytes != bytesNeeded && numBytes != -1)
+        {
+        	offset += numBytes;
+            bytesNeeded -= numBytes;
+            numBytes = inStream.read(blockBuffer, offset, bytesNeeded);
+        }
 
-        while (bytesNeeded > 0) {
-            long numBytes = inStream.read(blockBuffer, offset,
-                                               bytesNeeded);
+        //
+        // NOTE
+        // We have fit EOF, and the block is not full!
+        //
+        // This is a broken archive. It does not follow the standard
+        // blocking algorithm. However, because we are generous, and
+        // it requires little effort, we will simply ignore the error
+        // and continue as if the entire block were read. This does
+        // not appear to break anything upstream. We used to return
+        // false in this case.
+        //
+        // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
+        //
+        if (numBytes == -1)
+        {
+            // See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924
+        	// Did the first read and got EOF, so return EOF
+            if (offset == 0)
+            {
+            	return false;
+            }
 
+            // However, just leaving the unread portion of the buffer dirty does
+            // cause problems in some cases.  This problem is described in
+            // http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
             //
-            // NOTE
-            // We have fit EOF, and the block is not full!
-            //
-            // This is a broken archive. It does not follow the standard
-            // blocking algorithm. However, because we are generous, and
-            // it requires little effort, we will simply ignore the error
-            // and continue as if the entire block were read. This does
-            // not appear to break anything upstream. We used to return
-            // false in this case.
-            //
-            // Thanks to 'Yohann.Roussel@alcatel.fr' for this fix.
-            //
-            if (numBytes == -1) {
-                if (offset == 0) {
-                    // Ensure that we do not read gigabytes of zeros
-                    // for a corrupt tar file.
-                    // See http://issues.apache.org/bugzilla/show_bug.cgi?id=39924
-                    return false;
-                }
-                // However, just leaving the unread portion of the buffer dirty does
-                // cause problems in some cases.  This problem is described in
-                // http://issues.apache.org/bugzilla/show_bug.cgi?id=29877
-                //
-                // The solution is to fill the unused portion of the buffer with zeros.
+            // The solution is to fill the unused portion of the buffer with zeros.
 
-                Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0);
-
-                break;
-            }
-
-            offset += numBytes;
-            bytesNeeded -= numBytes;
-
-            if (numBytes != blockSize) {
-                // TODO: Incomplete Read occured - throw exception?
-            }
+            Arrays.fill(blockBuffer, offset, offset + bytesNeeded, (byte) 0);
         }
 
-        currBlkIdx++;
+        currBlkIdx += 1;
+        currRecIdx =  0;
 
         return true;
     }
@@ -293,11 +320,9 @@
      * @throws IOException on error
      */
     public void writeRecord(byte[] record) throws IOException {
-        if (outStream == null) {
-            if (inStream == null){
+        if (outStream == null)
+        {
                 throw new IOException("Output buffer is closed");
-            }
-            throw new IOException("writing to an input buffer");
         }
 
         if (record.length != recordSize) {
@@ -329,10 +354,7 @@
      */
     public void writeRecord(byte[] buf, int offset) throws IOException {
         if (outStream == null) {
-            if (inStream == null){
-                throw new IOException("Output buffer is closed");
-            }
-            throw new IOException("writing to an input buffer");
+        	throw new IOException("Output buffer is closed");
         }
 
         if ((offset + recordSize) > buf.length) {
@@ -355,11 +377,9 @@
 
     /**
      * Write a TarBuffer block to the archive.
+     * outStream cannot be null
      */
     private void writeBlock() throws IOException {
-        if (outStream == null) {
-            throw new IOException("writing to an input buffer");
-        }
 
         outStream.write(blockBuffer, 0, blockSize);
         outStream.flush();
