Index: /trunk/include/VBox/ssm.h
===================================================================
--- /trunk/include/VBox/ssm.h	(revision 23588)
+++ /trunk/include/VBox/ssm.h	(revision 23589)
@@ -621,4 +621,89 @@
 
 /** @} */
+
+
+/**
+ * SSM stream method table.
+ *
+ * This is used for live migration as well as internally in SSM.
+ */
+typedef struct SSMSTRMOPS
+{
+    /** Struct magic + version (SSMSTRMOPS_VERSION). */
+    uint32_t    u32Version;
+
+    /**
+     * Write bytes to the stream.
+     *
+     * @returns VBox status code.
+     * @param   pvUser              The user argument.
+     * @param   offStream           The stream offset we're (supposed to be) at.
+     * @param   pvBuf               Pointer to the data.
+     * @param   cbToWrite           The number of bytes to write.
+     */
+    DECLCALLBACKMEMBER(int, pfnWrite)(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite);
+
+    /**
+     * Read bytes to the stream.
+     *
+     * @returns VBox status code.
+     * @param   pvUser              The user argument.
+     * @param   offStream           The stream offset we're (supposed to be) at.
+     * @param   pvBuf               Where to return the bytes.
+     * @param   cbToRead            The number of bytes to read.
+     * @param   pcbRead             Where to return the number of bytes actually
+     *                              read.  This may differ from cbToRead when the
+     *                              end of the stream is encountered.
+     */
+    DECLCALLBACKMEMBER(int, pfnRead)(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead);
+
+    /**
+     * Seeks in the stream.
+     *
+     * @returns VBox status code.
+     * @retval  VERR_NOT_SUPPORTED if the stream doesn't support this action.
+     *
+     * @param   pvUser              The user argument.
+     * @param   offSeek             The seek offset.
+     * @param   uMethod             RTFILE_SEEK_BEGIN, RTFILE_SEEK_END or
+     *                              RTFILE_SEEK_CURRENT.
+     * @param   poffActual          Where to store the new file position. Optional.
+     */
+    DECLCALLBACKMEMBER(int, pfnSeek)(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual);
+
+    /**
+     * Get the current stream position.
+     *
+     * @returns The correct stream position.
+     * @param   pvUser              The user argument.
+     */
+    DECLCALLBACKMEMBER(uint64_t, pfnTell)(void *pvUser);
+
+    /**
+     * Get the size/length of the stream.
+     *
+     * @returns VBox status code.
+     * @retval  VERR_NOT_SUPPORTED if the stream doesn't support this action.
+     *
+     * @param   pvUser              The user argument.
+     * @param   pcb                 Where to return the size/length.
+     */
+    DECLCALLBACKMEMBER(int, pfnSize)(void *pvUser, uint64_t *pcb);
+
+    /**
+     * Close the stream.
+     *
+     * @returns VBox status code.
+     * @param   pvUser              The user argument.
+     */
+    DECLCALLBACKMEMBER(int, pfnClose)(void *pvUser);
+
+    /** Struct magic + version (SSMSTRMOPS_VERSION). */
+    uint32_t    u32EndVersion;
+} SSMSTRMOPS;
+/** Pointer to a const SSM stream method table. */
+typedef SSMSTRMOPS const *PCSSMSTRMOPS;
+/** Struct magic + version (SSMSTRMOPS_VERSION). */
+#define SSMSTRMOPS_VERSION  UINT32_C(0x55aa0001)
 
 
Index: /trunk/src/VBox/VMM/SSM.cpp
===================================================================
--- /trunk/src/VBox/VMM/SSM.cpp	(revision 23588)
+++ /trunk/src/VBox/VMM/SSM.cpp	(revision 23589)
@@ -353,4 +353,5 @@
 } SSMSTATE;
 
+
 /** Pointer to a SSM stream buffer. */
 typedef struct SSMSTRMBUF *PSSMSTRMBUF;
@@ -381,6 +382,9 @@
 typedef struct SSMSTRM
 {
-    /** The file handle. */
-    RTFILE                  hFile;
+    /** The stream method table. */
+    PCSSMSTRMOPS            pOps;
+    /** The user argument for the stream methods.
+     * For file based streams, this is the file handle and not a pointer. */
+    void                   *pvUser;
 
     /** Write (set) or read (clear) stream. */
@@ -1627,4 +1631,76 @@
 
 /**
+ * @copydoc SSMSTRMOPS::pfnWrite
+ */
+static DECLCALLBACK(int) ssmR3FileWrite(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)
+{
+    Assert(RTFileTell((RTFILE)(uintptr_t)pvUser) == offStream); NOREF(offStream);
+    return RTFileWriteAt((RTFILE)(uintptr_t)pvUser, offStream, pvBuf, cbToWrite, NULL); /** @todo use RTFileWrite */
+}
+
+
+/**
+ * @copydoc SSMSTRMOPS::pfnRead
+ */
+static DECLCALLBACK(int) ssmR3FileRead(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)
+{
+    Assert(RTFileTell((RTFILE)(uintptr_t)pvUser) == offStream); NOREF(offStream);
+    return RTFileRead((RTFILE)(uintptr_t)pvUser, pvBuf, cbToRead, pcbRead);
+}
+
+
+/**
+ * @copydoc SSMSTRMOPS::pfnSeek
+ */
+static DECLCALLBACK(int) ssmR3FileSeek(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)
+{
+    return RTFileSeek((RTFILE)(uintptr_t)pvUser, offSeek, uMethod, poffActual);
+}
+
+
+/**
+ * @copydoc SSMSTRMOPS::pfnTell
+ */
+static DECLCALLBACK(uint64_t) ssmR3FileTell(void *pvUser)
+{
+    return RTFileTell((RTFILE)(uintptr_t)pvUser);
+}
+
+
+/**
+ * @copydoc SSMSTRMOPS::pfnSize
+ */
+static DECLCALLBACK(int) ssmR3FileSize(void *pvUser, uint64_t *pcb)
+{
+    return RTFileGetSize((RTFILE)(uintptr_t)pvUser, pcb);
+}
+
+
+/**
+ * @copydoc SSMSTRMOPS::pfnClose
+ */
+static DECLCALLBACK(int) ssmR3FileClose(void *pvUser)
+{
+    return RTFileClose((RTFILE)(uintptr_t)pvUser);
+}
+
+
+/**
+ * Method table for a file based stream.
+ */
+static SSMSTRMOPS const g_ssmR3FileOps =
+{
+    SSMSTRMOPS_VERSION,
+    ssmR3FileWrite,
+    ssmR3FileRead,
+    ssmR3FileSeek,
+    ssmR3FileTell,
+    ssmR3FileSize,
+    ssmR3FileClose,
+    SSMSTRMOPS_VERSION
+};
+
+
+/**
  * Opens a file stream.
  *
@@ -1645,7 +1721,10 @@
                         ? RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE
                         : RTFILE_O_READ      | RTFILE_O_OPEN           | RTFILE_O_DENY_WRITE;
-        rc = RTFileOpen(&pStrm->hFile, pszFilename, fFlags);
+        RTFILE hFile;
+        rc = RTFileOpen(&hFile, pszFilename, fFlags);
         if (RT_SUCCESS(rc))
         {
+            pStrm->pOps   = &g_ssmR3FileOps;
+            pStrm->pvUser = (void *)(uintptr_t)hFile;
             pStrm->fWrite = fWrite;
             return VINF_SUCCESS;
@@ -1918,5 +1997,5 @@
 
         /* flush */
-        int rc = RTFileWriteAt(pStrm->hFile, pCur->offStream, &pCur->abData[0], pCur->cb, NULL);
+        int rc = pStrm->pOps->pfnWrite(pStrm->pvUser, pCur->offStream, &pCur->abData[0], pCur->cb);
         if (    RT_FAILURE(rc)
             &&  ssmR3StrmSetError(pStrm, rc))
@@ -1963,8 +2042,9 @@
     }
 
-    int rc = RTFileClose(pStrm->hFile);
+    int rc = pStrm->pOps->pfnClose(pStrm->pvUser);
     if (RT_FAILURE(rc))
         ssmR3StrmSetError(pStrm, rc);
-    pStrm->hFile = NIL_RTFILE;
+    pStrm->pOps   = NULL;
+    pStrm->pvUser = NULL;
 
     rc = pStrm->rc;
@@ -2152,5 +2232,5 @@
     if (pStrm->fNeedSeek)
     {
-        rc = RTFileSeek(pStrm->hFile, pStrm->offNeedSeekTo, RTFILE_SEEK_BEGIN, NULL);
+        rc = pStrm->pOps->pfnSeek(pStrm->pvUser, pStrm->offNeedSeekTo, RTFILE_SEEK_BEGIN, NULL);
         if (RT_FAILURE(rc))
         {
@@ -2170,7 +2250,7 @@
         return pStrm->rc;
 
-    pBuf->offStream = RTFileTell(pStrm->hFile);
+    pBuf->offStream = pStrm->pOps->pfnTell(pStrm->pvUser);
     size_t cbRead   = sizeof(pBuf->abData);
-    rc = RTFileRead(pStrm->hFile, &pBuf->abData[0], cbRead, &cbRead);
+    rc = pStrm->pOps->pfnRead(pStrm->pvUser, pBuf->offStream, &pBuf->abData[0], cbRead, &cbRead);
     if (    RT_SUCCESS(rc)
         &&  cbRead > 0)
@@ -2406,5 +2486,5 @@
 
     uint64_t offStream;
-    int rc = RTFileSeek(pStrm->hFile, off, uMethod, &offStream);
+    int rc = pStrm->pOps->pfnSeek(pStrm->pvUser, off, uMethod, &offStream);
     if (RT_SUCCESS(rc))
     {
@@ -2466,5 +2546,5 @@
 {
     uint64_t cbFile;
-    int rc = RTFileGetSize(pStrm->hFile, &cbFile);
+    int rc = pStrm->pOps->pfnSize(pStrm->pvUser, &cbFile);
     AssertLogRelRCReturn(rc, UINT64_MAX);
     return cbFile;
@@ -2480,5 +2560,5 @@
 static bool ssmR3StrmIsFile(PSSMSTRM pStrm)
 {
-    return pStrm->hFile != NIL_RTFILE;
+    return pStrm->pOps == &g_ssmR3FileOps;
 }
 
@@ -2501,5 +2581,5 @@
 static int ssmR3StrmPeekAt(PSSMSTRM pStrm, RTFOFF off, void *pvBuf, size_t cbToRead, uint64_t *poff)
 {
-    AssertReturn(!pStrm->fWrite && pStrm->hFile != NIL_RTFILE, VERR_NOT_SUPPORTED);
+    AssertReturn(!pStrm->fWrite, VERR_NOT_SUPPORTED);
     AssertReturn(pStrm->hIoThread == NIL_RTTHREAD, VERR_WRONG_ORDER);
 
@@ -2509,8 +2589,12 @@
         pStrm->offNeedSeekTo = pStrm->offCurStream + (pStrm->pCur ? pStrm->pCur->cb : 0);
     }
-
-    int rc = RTFileSeek(pStrm->hFile, off, off >= 0 ? RTFILE_SEEK_BEGIN : RTFILE_SEEK_END, poff);
+    uint64_t offActual;
+    int rc = pStrm->pOps->pfnSeek(pStrm->pvUser, off, off >= 0 ? RTFILE_SEEK_BEGIN : RTFILE_SEEK_END, &offActual);
     if (RT_SUCCESS(rc))
-        rc = RTFileRead(pStrm->hFile, pvBuf, cbToRead, NULL);
+    {
+        if (poff)
+            *poff = offActual;
+        rc = pStrm->pOps->pfnRead(pStrm->pvUser, offActual, pvBuf, cbToRead, NULL);
+    }
 
     return rc;
