Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 33902)
+++ /trunk/include/iprt/err.h	(revision 33903)
@@ -1294,4 +1294,6 @@
 /** The compression method is unsupported. */
 #define VERR_ZIP_UNSUPPORTED_METHOD             (-954)
+/** The compressed data started with a bad header. */
+#define VERR_ZIP_BAD_HEADER                     (-955)
 /** @} */
 
Index: /trunk/include/iprt/vfs.h
===================================================================
--- /trunk/include/iprt/vfs.h	(revision 33902)
+++ /trunk/include/iprt/vfs.h	(revision 33903)
@@ -211,9 +211,9 @@
  * @param   pvBuf           Where to store the read bytes.
  * @param   cbToRead        The number of bytes to read.
- * @param   pcbRead         Where to store the number of bytes actually read.
- *                          If this is NULL, the call will block until @a
- *                          cbToRead bytes are available.  If this is non-NULL,
- *                          the call will not block and return what is currently
- *                          avaiable.
+ * @param   pcbRead         Where to always store the number of bytes actually
+ *                          read.  If this is NULL, the call will block until
+ *                          @a cbToRead bytes are available.  If this is
+ *                          non-NULL, the call will not block and return what
+ *                          is currently avaiable.
  * @sa      RTFileRead, RTPipeRead, RTPipeReadBlocking, RTSocketRead
  */
@@ -227,9 +227,10 @@
  * @param   pvBuf           The bytes to write.
  * @param   cbToWrite       The number of bytes to write.
- * @param   pcbWritten      Where to store the number of bytes actually written.
- *                          If this is NULL, the call will block until @a
- *                          cbToWrite bytes are available.  If this is non-NULL,
- *                          the call will not block and return after writing
- *                          what is possible.
+ * @param   pcbWritten      Where to always store the number of bytes actually
+ *                          written.  If this is NULL, the call will block
+ *                          until
+ *                          @a cbToWrite bytes are available.  If this is
+ *                          non-NULL, the call will not block and return after
+ *                          writing what is possible.
  * @sa      RTFileWrite, RTPipeWrite, RTPipeWriteBlocking, RTSocketWrite
  */
@@ -240,4 +241,17 @@
  *
  * @returns IPRT status code.
+ * @retval  VINF_SUCCESS and the number of bytes read written to @a pcbRead.
+ * @retval  VINF_TRY_AGAIN if @a fBlocking is @c false, @a pcbRead is not NULL,
+ *          and no data was available. @a *pcbRead will be set to 0.
+ * @retval  VINF_EOF when trying to read __beyond__ the end of the stream and
+ *          @a pcbRead is not NULL (it will be set to the number of bytes read,
+ *          or 0 if the end of the stream was reached before this call).
+ *          When the last byte of the read request is the last byte in the
+ *          stream, this status code will not be used.  However, VINF_EOF is
+ *          returned when attempting to read 0 bytes while standing at the end
+ *          of the stream.
+ * @retval  VERR_EOF when trying to read __beyond__ the end of the stream and
+ *          @a pcbRead is NULL.
+ *
  * @param   hVfsIos         The VFS I/O stream handle.
  * @param   pSgBuf          Pointer to a scatter buffer descriptor.  The number
@@ -246,7 +260,7 @@
  * @param   fBlocking       Whether the call is blocking (@c true) or not.  If
  *                          not, the @a pcbRead parameter must not be NULL.
- * @param   pcbRead         Where to store the number of bytes actually read.
- *                          This can be NULL if @a fBlocking is true.
- * @sa      RTFileSgRead, RTSocketSgRead
+ * @param   pcbRead         Where to always store the number of bytes actually
+ *                          read.  This can be NULL if @a fBlocking is true.
+ * @sa      RTFileSgRead, RTSocketSgRead, RTPipeRead, RTPipeReadBlocking
  */
 RTDECL(int)         RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead);
@@ -262,6 +276,6 @@
  * @param   fBlocking       Whether the call is blocking (@c true) or not.  If
  *                          not, the @a pcbWritten parameter must not be NULL.
- * @param   pcbRead         Where to store the number of bytes actually written.
- *                          This can be NULL if @a fBlocking is true.
+ * @param   pcbRead         Where to always store the number of bytes actually
+ *                          written.  This can be NULL if @a fBlocking is true.
  * @sa      RTFileSgWrite, RTSocketSgWrite
  */
Index: /trunk/include/iprt/vfslowlevel.h
===================================================================
--- /trunk/include/iprt/vfslowlevel.h	(revision 33902)
+++ /trunk/include/iprt/vfslowlevel.h	(revision 33903)
@@ -429,5 +429,5 @@
      * Reads from the file/stream.
      *
-     * @returns IPRT status code.
+     * @returns IPRT status code. See RTVfsIoStrmRead.
      * @param   pvThis      The implementation specific file data.
      * @param   off         Where to read at, -1 for the current position.
@@ -436,7 +436,9 @@
      * @param   fBlocking   If @c true, the call is blocking, if @c false it
      *                      should not block.
-     * @param   pcbRead     Where return the number of bytes actually read.  If
-     *                      NULL, try read all and fail if incomplete.
-     * @sa      RTFileRead, RTFileReadAt.
+     * @param   pcbRead     Where return the number of bytes actually read.
+     *                      This is set it 0 by the caller.  If NULL, try read
+     *                      all and fail if incomplete.
+     * @sa      RTVfsIoStrmRead, RTVfsIoStrmSgRead, RTVfsFileRead,
+     *          RTVfsFileReadAt, RTFileRead, RTFileReadAt.
      */
     DECLCALLBACKMEMBER(int, pfnRead)(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead);
@@ -453,7 +455,7 @@
      * @param   fBlocking   If @c true, the call is blocking, if @c false it
      *                      should not block.
-     * @param   pcbWrite    Where to return the number of bytes actually
-     *                      written.  If  NULL, try write it all and fail if
-     *                      incomplete.
+     * @param   pcbWritten  Where to return the number of bytes actually
+     *                      written.  This is set it 0 by the caller.  If
+     *                      NULL, try write it all and fail if incomplete.
      * @sa      RTFileWrite, RTFileWriteAt.
      */
Index: /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 33902)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp	(revision 33903)
@@ -914,4 +914,7 @@
 RTDECL(int)         RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, size_t *pcbRead)
 {
+    AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
+    if (pcbRead)
+        *pcbRead = 0;
     RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
@@ -931,4 +934,7 @@
 RTDECL(int)         RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
 {
+    AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
+    if (pcbWritten)
+        *pcbWritten = 0;
     RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
@@ -948,9 +954,12 @@
 RTDECL(int)         RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
 {
+    AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
+    if (pcbRead)
+        *pcbRead = 0;
     RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
     AssertPtr(pSgBuf);
-    AssertReturn(fBlocking || VALID_PTR(pcbRead), VERR_INVALID_PARAMETER);
+    AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
 
     RTVFS_WRITE_LOCK(pThis->hSemRW);
@@ -963,9 +972,12 @@
 RTDECL(int)         RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
 {
+    AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
+    if (pcbWritten)
+        *pcbWritten = 0;
     RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
     AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
     AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
     AssertPtr(pSgBuf);
-    AssertReturn(fBlocking || VALID_PTR(pcbWritten), VERR_INVALID_PARAMETER);
+    AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
 
     RTVFS_WRITE_LOCK(pThis->hSemRW);
Index: /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 33902)
+++ /trunk/src/VBox/Runtime/common/vfs/vfsstdfile.cpp	(revision 33903)
@@ -84,4 +84,48 @@
 
 /**
+ * RTFileRead and RTFileReadAt does not return VINF_EOF or VINF_TRY_AGAIN, this
+ * function tries to fix this as best as it can.
+ *
+ * This fixing can be subject to races if some other thread or process is
+ * modifying the file size between the read and our size query here.
+ *
+ * @returns VINF_SUCCESS, VINF_EOF or VINF_TRY_AGAIN.
+ * @param   pThis               The instance data.
+ * @param   off                 The offset parameter.
+ * @param   cbToRead            The number of bytes attempted read .
+ * @param   cbActuallyRead      The number of bytes actually read.
+ */
+DECLINLINE(int) rtVfsStdFile_ReadFixRC(PRTVFSSTDFILE pThis, RTFOFF off, size_t cbToRead, size_t cbActuallyRead)
+{
+    /* If the read returned less bytes than requested, it means the end of the
+       file has been reached. */
+    if (cbToRead > cbActuallyRead)
+        return VINF_EOF;
+
+    /* The other case here is the very special zero byte read at the end of the
+       file, where we're supposed to indicate EOF. */
+    if (cbToRead > 0)
+        return VINF_SUCCESS;
+
+    uint64_t cbFile;
+    int rc = RTFileGetSize(pThis->hFile, &cbFile);
+    if (RT_FAILURE(rc))
+        return rc;
+
+    uint64_t off2;
+    if (off >= 0)
+        off2 = off;
+    else
+    {
+        rc = RTFileSeek(pThis->hFile, 0, RTFILE_SEEK_CURRENT, &off2);
+        if (RT_FAILURE(rc))
+            return rc;
+    }
+
+    return off2 >= cbFile ? VINF_EOF : VINF_SUCCESS;
+}
+
+
+/**
  * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
  */
@@ -95,40 +139,42 @@
     {
         if (off < 0)
-            rc = RTFileRead(pThis->hFile, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
+            rc = RTFileRead(  pThis->hFile,      pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
         else
             rc = RTFileReadAt(pThis->hFile, off, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, pcbRead);
+        if (rc == VINF_SUCCESS && pcbRead)
+            rc = rtVfsStdFile_ReadFixRC(pThis, off, pSgBuf->paSegs[0].cbSeg, *pcbRead);
     }
     else
     {
+        size_t  cbSeg      = 0;
         size_t  cbRead     = 0;
-        size_t  cbReadSeg;
-        size_t *pcbReadSeg = pcbRead ? &cbReadSeg : NULL;
+        size_t  cbReadSeg  = 0;
         rc = VINF_SUCCESS;
 
         for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
         {
-            void   *pvSeg  = pSgBuf->paSegs[iSeg].pvSeg;
-            size_t  cbSeg  = pSgBuf->paSegs[iSeg].cbSeg;
-
-            cbReadSeg = 0;
+            void *pvSeg = pSgBuf->paSegs[iSeg].pvSeg;
+            cbSeg       = pSgBuf->paSegs[iSeg].cbSeg;
+
+            cbReadSeg = cbSeg;
             if (off < 0)
-                rc = RTFileRead(pThis->hFile, pvSeg, cbSeg, pcbReadSeg);
+                rc = RTFileRead(  pThis->hFile,      pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
             else
-            {
-                rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbReadSeg);
-                off += cbSeg;
-            }
+                rc = RTFileReadAt(pThis->hFile, off, pvSeg, cbSeg, pcbRead ? &cbReadSeg : NULL);
             if (RT_FAILURE(rc))
                 break;
-            if (pcbRead)
-            {
-                cbRead += cbReadSeg;
-                if (cbReadSeg != cbSeg)
-                    break;
-            }
+            if (off < 0)
+                off += cbReadSeg;
+            cbRead  += cbReadSeg;
+            if ((pcbRead && cbReadSeg != cbSeg) || rc != VINF_SUCCESS)
+                break;
         }
 
         if (pcbRead)
+        {
             *pcbRead = cbRead;
+            if (rc == VINF_SUCCESS)
+                rc = rtVfsStdFile_ReadFixRC(pThis, off, cbSeg, cbReadSeg);
+        }
     }
 
