SSM.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/** @file
*
* SSM - Saved State Manager.
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/** @page pg_ssm SSM - The Saved State Manager
*
* The Saved State Manager (SSM) implements facilities for saving and loading
* a VM state in a structural manner using callbacks for each collection of
* data which needs saving.
*
* At init time each of the VM components will register data entities which
* they need to save and restore. Each entity have a unique name (ascii) and
* a set of callbacks associated with it. The name will be used to identify
* the entity during restore. The callbacks are for the two operations, save
* and restore. There are three callbacks for each of the two - a prepare,
* a execute and a what-now.
*
* The SSM provides a number of APIs for encoding and decoding the data.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SSM
#include "SSMInternal.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Start structure magic. (Isacc Asimov) */
#define SSMR3STRUCT_BEGIN 0x19200102
/** End structure magic. (Isacc Asimov) */
#define SSMR3STRUCT_END 0x19920406
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
typedef enum SSMSTATE
{
SSMSTATE_SAVE_PREP = 1,
} SSMSTATE;
/**
* Handle structure.
*/
typedef struct SSMHANDLE
{
/** The file handle. */
/** The VM handle. */
/** The current operation. */
/** What to do after save completes. (move the enum) */
/** The current rc of the save operation. */
int rc;
/** The compressor of the current data unit. */
/** The decompressor of the current data unit. */
/** Number of bytes left in the current data unit. */
/** Pointer to the progress callback function. */
/** User specified arguemnt to the callback function. */
void *pvUser;
/** Next completion percentage. (corresponds to offEstProgress) */
unsigned uPercent;
/** The position of the next progress callback in the estimated file. */
/** The estimated total byte count.
* (Only valid after the prep.) */
/** Current position in the estimated file. */
/** End of current unit in the estimated file. */
/** the amount of % we reserve for the 'prepare' phase */
unsigned uPercentPrepare;
/** the amount of % we reserve for the 'done' stage */
unsigned uPercentDone;
} SSMHANDLE;
/**
* Header of the saved state file.
*/
typedef struct SSMFILEHDR
{
/** Magic string which identifies this file as a version of VBox saved state file format. */
char achMagic[32];
/** The size of this file. Used to check
* whether the save completed and that things are fine otherwise. */
/** File checksum. The actual calculation skips past the u32CRC field. */
/** The machine UUID. (Ignored if NIL.) */
} SSMFILEHDR, *PSSMFILEHDR;
/** Saved state file magic base string. */
#define SSMFILEHDR_MAGIC_BASE "\177VirtualBox SavedState "
/** Saved state file v1.0 magic. */
#define SSMFILEHDR_MAGIC_V1 "\177VirtualBox SavedState V1.0\n"
/**
* Data unit header.
*/
typedef struct SSMFILEUNITHDR
{
/** Magic. */
char achMagic[8];
/** Number of bytes in this data unit including the header. */
/** Data version. */
/** Instance number. */
/** Size of the data unit name including the terminator. (bytes) */
/** Data unit name. */
char szName[1];
/** Data unit magic. */
#define SSMFILEUNITHDR_MAGIC "\nUnit\n"
/** Data end marker magic. */
#define SSMFILEUNITHDR_END "\nTheEnd"
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static int smmr3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, PSSMUNIT *ppUnit);
/**
* Internal registration worker.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance id.
* @param u32Version The data unit version.
* @param cbGuess The guessed data unit size.
* @param ppUnit Where to store the insterted unit node.
* Caller must fill in the missing details.
*/
static int smmr3Register(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess, PSSMUNIT *ppUnit)
{
/*
* Walk to the end of the list checking for duplicates as we go.
*/
while (pUnit)
{
{
return VERR_SSM_UNIT_EXISTS;
}
/* next */
}
/*
* Allocate new node.
*/
if (!pUnit)
return VERR_NO_MEMORY;
/*
* Fill in (some) data. (Stuff is zero'ed.)
*/
/*
* Insert
*/
if (pUnitPrev)
else
return VINF_SUCCESS;
}
/**
* Register a PDM Devices data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDevIns Device instance.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
SSMR3DECL(int) SSMR3Register(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
{
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
/**
* Register a PDM driver data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDrvIns Driver instance.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
SSMR3DECL(int) SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
{
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
/**
* Register a internal data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
*/
SSMR3DECL(int) SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
{
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
/**
* Register an external data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @param u32Version Data layout version number.
* @param cbGuess The approximate amount of data in the unit.
* Only for progress indicators.
* @param pfnSavePrep Prepare save callback, optional.
* @param pfnSaveExec Execute save callback, optional.
* @param pfnSaveDone Done save callback, optional.
* @param pfnLoadPrep Prepare load callback, optional.
* @param pfnLoadExec Execute load callback, optional.
* @param pfnLoadDone Done load callback, optional.
* @param pvUser User argument.
*/
SSMR3DECL(int) SSMR3RegisterExternal(PVM pVM, const char *pszName, uint32_t u32Instance, uint32_t u32Version, size_t cbGuess,
PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser)
{
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
/**
* Deregister one or more PDM Device data units.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDevIns Device instance.
* @param pszName Data unit name.
* Use NULL to deregister all data units for that device instance.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique.
* @remark Only for dynmaic data units and dynamic unloaded modules.
*/
SSMR3DECL(int) SSMR3Deregister(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t u32Instance)
{
/*
* Validate input.
*/
if (!pDevIns)
{
AssertMsgFailed(("pDevIns is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
while (pUnit)
{
&& ( !pszName
)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
if (pszName)
return VINF_SUCCESS;
rc = VINF_SUCCESS;
continue;
}
else if (pszName)
{
AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
return VERR_SSM_UNIT_NOT_OWNER;
}
}
/* next */
}
return rc;
}
/**
* Deregister one ore more PDM Driver data units.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pDrvIns Driver instance.
* @param pszName Data unit name.
* Use NULL to deregister all data units for that driver instance.
* @param u32Instance The instance identifier of the data unit.
* This must together with the name be unique. Ignored if pszName is NULL.
* @remark Only for dynmaic data units and dynamic unloaded modules.
*/
SSMR3DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t u32Instance)
{
/*
* Validate input.
*/
if (!pDrvIns)
{
AssertMsgFailed(("pDrvIns is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
while (pUnit)
{
&& ( !pszName
)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
if (pszName)
return VINF_SUCCESS;
rc = VINF_SUCCESS;
continue;
}
else if (pszName)
{
AssertMsgFailed(("Caller is not owner! Owner=%p Caller=%p %s\n",
return VERR_SSM_UNIT_NOT_OWNER;
}
}
/* next */
}
return rc;
}
/**
* Deregister a internal data unit.
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszName Data unit name.
* @remark Only for dynmaic data units.
*/
{
/*
* Validate input.
*/
if (!pszName)
{
AssertMsgFailed(("pszName is NULL!\n"));
return VERR_INVALID_PARAMETER;
}
/*
* Search the list.
*/
int rc = VERR_SSM_UNIT_NOT_FOUND;
while (pUnit)
{
{
/*
* Unlink it, advance pointer, and free the node.
*/
if (pUnitPrev)
else
return VINF_SUCCESS;
}
/* next */
}
return rc;
}
/**
* Calculate the checksum of a file portion.
*
*
* @returns VBox status.
* @param File Handle to the file.
* @param cbFile Size of the file.
* @param pu32CRC Where to store the calculated checksum.
*/
{
/*
* Allocate a buffer.
*/
if (!pvBuf)
return VERR_NO_TMP_MEMORY;
/*
* Loop reading and calculating CRC32.
*/
int rc = VINF_SUCCESS;
while (cbFile)
{
/* read chunk */
if (VBOX_FAILURE(rc))
{
return rc;
}
/* update total */
/* calc crc32. */
}
/* store the calculated crc */
return VINF_SUCCESS;
}
/**
* Works the progress calculation.
*
* @param pSSM The SSM handle.
* @param cbAdvance Number of bytes to advance
*/
{
/* Can't advance it beyond the estimated end of the unit. */
/* uPercentPrepare% prepare, xx% exec, uPercentDone% done+crc */
{
if (pSSM->pfnProgress)
}
}
/**
* Start VM save operation.
* The caller must be the emulation thread!
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszFilename Name of the file to save the state in.
* @param enmAfter What is planned after a successful save operation.
* @param pfnProgress Progress callback. Optional.
* @param pvUser User argument for the progress callback.
*/
SSMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
{
LogFlow(("SSMR3Save: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
/*
* Validate input.
*/
{
return VERR_INVALID_PARAMETER;
}
/*
* Try open the file.
*/
/*
* The 'done' part might take much time:
* (1) Call the SaveDone function of each module
* (2) Calculate the Checksum
* (3) RTFileClose() will probably flush the write cache
*/
int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE);
if (VBOX_FAILURE(rc))
{
return rc;
}
/*
* Write header.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Clear the per unit flags.
*/
/*
* Do the prepare run.
*/
{
{
case SSMUNITTYPE_DEV:
{
}
break;
case SSMUNITTYPE_DRV:
{
}
break;
case SSMUNITTYPE_INTERNAL:
{
}
break;
case SSMUNITTYPE_EXTERNAL:
{
}
break;
}
if (VBOX_FAILURE(rc))
{
break;
}
}
/* Progress. */
if (pfnProgress)
/*
* Do the execute run.
*/
if (VBOX_SUCCESS(rc))
{
{
/*
* Estimate.
*/
/*
* Does this unit have a callback? If, not skip it.
*/
bool fSkip;
{
default: fSkip = true; break;
}
if (fSkip)
{
continue;
}
/*
* Write data unit header
*/
SSMFILEUNITHDR UnitHdr = { SSMFILEUNITHDR_MAGIC, 0, pUnit->u32Version, pUnit->u32Instance, pUnit->cchName + 1, { '\0' } };
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
{
/*
* Call the execute handler.
*/
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (VBOX_SUCCESS(rc))
{
/*
* Flush buffer / end compression stream.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Update header with correct length.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
}
}
}
else
{
break;
}
}
else
{
break;
}
}
}
if (VBOX_FAILURE(rc))
{
break;
}
} /* for each unit */
/* finish the progress. */
if (VBOX_SUCCESS(rc))
}
/* (progress should be pending 99% now) */
AssertMsg(VBOX_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
/*
* Do the done run.
*/
{
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (VBOX_FAILURE(rc))
{
}
}
/*
* Finalize the file if successfully saved.
*/
if (VBOX_SUCCESS(rc))
{
/* end record */
if (VBOX_SUCCESS(rc))
{
/* get size */
/* calc checksum */
rc = RTFileSeek(Handle.File, RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(Hdr.u32CRC), RTFILE_SEEK_BEGIN, NULL);
if (VBOX_SUCCESS(rc))
if (VBOX_SUCCESS(rc))
{
if (pfnProgress)
/*
* Write the update the header to the file.
*/
if (VBOX_SUCCESS(rc))
if (VBOX_SUCCESS(rc))
{
if (pfnProgress)
Log(("\n\n\n"));
Log(("\n\n\n"));
return VINF_SUCCESS;
}
}
}
}
}
/*
* Delete the file on failure and destroy any compressors.
*/
return rc;
}
/**
* Validates the integrity of a saved state file.
*
* @returns VBox status.
* @param File File to validate.
* The file position is undefined on return.
* @param pHdr Where to store the file header.
*/
{
/*
* Read the header.
*/
if (VBOX_FAILURE(rc))
{
return rc;
}
/*
* Verify the magic.
*/
{
return VERR_SSM_INTEGRITY_MAGIC;
}
{
Log(("SSM: Unknown file format version. magic=%.*s\n", sizeof(pHdr->achMagic) - 1, pHdr->achMagic));
return VERR_SSM_INTEGRITY_VERSION;
}
/*
* Verify the file size.
*/
if (VBOX_FAILURE(rc))
{
return rc;
}
{
return VERR_SSM_INTEGRITY_SIZE;
}
/*
* Verify the checksum.
*/
rc = RTFileSeek(File, RT_OFFSETOF(SSMFILEHDR, u32CRC) + sizeof(pHdr->u32CRC), RTFILE_SEEK_BEGIN, NULL);
if (VBOX_FAILURE(rc))
{
return rc;
}
if (VBOX_FAILURE(rc))
return rc;
{
return VERR_SSM_INTEGRITY_CRC;
}
/*
* Verify Virtual Machine UUID.
*/
/** @todo get machine uuids CFGGetUuid(, &Uuid); */
{
Log(("SSM: The UUID of the saved state doesn't match the running VM.\n"));
return VERR_SMM_INTEGRITY_MACHINE;
}
return VINF_SUCCESS;
}
/**
* Find a data unit by name.
*
* @returns Pointer to the unit.
* @returns NULL if not found.
* @param pVM VM handle.
* @param pszName Data unit name.
* @param u32Instance The data unit instance id.
*/
{
while ( pUnit
return pUnit;
}
/**
* Load VM save operation.
* The caller must be the emulation thread!
*
* @returns VBox status.
* @param pVM The VM handle.
* @param pszFilename Name of the file to save the state in.
* @param enmAfter What is planned after a successful save operation.
* @param pfnProgress Progress callback. Optional.
* @param pvUser User argument for the progress callback.
*/
SSMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser)
{
LogFlow(("SSMR3Load: pszFilename=%p:{%s} enmAfter=%d pfnProgress=%p pvUser=%p\n", pszFilename, pszFilename, enmAfter, pfnProgress, pvUser));
/*
* Validate input.
*/
if (enmAfter != SSMAFTER_RESUME)
{
return VERR_INVALID_PARAMETER;
}
/*
* Open the file.
*/
int rc = RTFileOpen(&Handle.File, pszFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
if (VBOX_FAILURE(rc))
{
return rc;
}
/*
* Read file header and validate it.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Clear the per unit flags.
*/
/*
* Do the prepare run.
*/
{
{
case SSMUNITTYPE_DEV:
{
}
break;
case SSMUNITTYPE_DRV:
{
}
break;
case SSMUNITTYPE_INTERNAL:
{
}
break;
case SSMUNITTYPE_EXTERNAL:
{
}
break;
}
if (VBOX_FAILURE(rc))
{
break;
}
}
/* pending 2% */
if (pfnProgress)
/*
* Do the execute run.
*/
if (VBOX_SUCCESS(rc))
if (VBOX_SUCCESS(rc))
{
for (;;)
{
/*
* Save the current file position and read the data unit header.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Check the magic and see if it's valid and whether it is a end header or not.
*/
{
{
/* Complete the progress bar (pending 99% afterwards). */
break;
}
LogRel(("SSM: Invalid unit magic at offset %#llx (%lld), '%.*s'!\n",
break;
}
/*
* Read the name.
* Adjust the name buffer first.
*/
{
if (pszName)
}
if (pszName)
{
if (VBOX_SUCCESS(rc))
{
{
/*
* Progress
*/
/*
* Find the data unit in our internal table.
*/
if (pUnit)
{
/*
* Call the execute handler.
*/
{
case SSMUNITTYPE_DEV:
else
break;
case SSMUNITTYPE_DRV:
else
break;
case SSMUNITTYPE_INTERNAL:
else
break;
case SSMUNITTYPE_EXTERNAL:
{
if (!rc)
}
else
break;
}
if (rc != VERR_SSM_NO_LOAD_EXEC)
{
/*
* Close the reader stream.
*/
if (Handle.pZipDecomp)
if (VBOX_SUCCESS(rc))
{
/*
* Now, we'll check the current position to see if all, or
* more than all, the data was read.
*
* Note! Because of buffering / compression we'll only see the
* really bad ones here.
*/
if (i64Diff < 0)
{
}
else if (i64Diff > 0)
{
break;
}
/* Advance the progress bar to the end of the block. */
}
else
{
break;
}
}
else
{
break;
}
}
else
{
break;
}
}
else
{
break;
}
}
}
else
}
/*
* I/O errors ends up here (yea, I know, very nice programming).
*/
if (VBOX_FAILURE(rc))
{
break;
}
}
}
/* (progress should be pending 99% now) */
AssertMsg(VBOX_FAILURE(rc) || Handle.uPercent == (101-Handle.uPercentDone), ("%d\n", Handle.uPercent));
/*
* Do the done run.
*/
{
rc = VINF_SUCCESS;
{
case SSMUNITTYPE_DEV:
break;
case SSMUNITTYPE_DRV:
break;
case SSMUNITTYPE_INTERNAL:
break;
case SSMUNITTYPE_EXTERNAL:
break;
}
if (VBOX_FAILURE(rc))
{
}
}
/* progress */
if (pfnProgress)
}
/*
* Done
*/
if (VBOX_SUCCESS(rc))
{
/* progress */
if (pfnProgress)
Log(("\n\n\n"));
Log(("\n\n\n"));
}
return rc;
}
/**
* Validates a file as a validate SSM saved state.
*
* This will only verify the file format, the format and content of individual
* data units are not inspected.
*
* @returns VINF_SUCCESS if valid.
* @returns VBox status code on other failures.
* @param pszFilename The path to the file to validate.
*/
{
/*
* Try open the file and validate it.
*/
if (VBOX_SUCCESS(rc))
{
}
else
return rc;
}
/**
* Opens a saved state file for reading.
*
* @returns VBox status code.
* @param pszFilename The path to the saved state file.
* @param fFlags Open flags. Reserved, must be 0.
* @param ppSSM Where to store the SSM handle.
*/
{
LogFlow(("SSMR3Open: pszFilename=%p:{%s} fFlags=%#x ppSSM=%p\n", pszFilename, pszFilename, fFlags, ppSSM));
/*
* Validate input.
*/
/*
* Allocate a handle.
*/
/*
* Try open the file and validate it.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
{
//pSSM->pVM = NULL;
//pSSM->rc = VINF_SUCCESS;
//pSSM->pZipComp = NULL;
//pSSM->pZipDecomp = NULL;
//pSSM->cbUnitLeft = 0;
//pSSM->pfnProgress = NULL;
//pSSM->pvUser = NULL;
//pSSM->uPercent = 0;
//pSSM->offEstProgress= 0;
//pSSM->cbEstTotal = 0;
//pSSM->offEst = 0;
//pSSM->offEstUnitEnd = 0;
return VINF_SUCCESS;
}
}
else
return rc;
}
/**
* Closes a saved state file opened by SSMR3Open().
*
* @returns VBox status code.
* @param pSSM The SSM handle returned by SSMR3Open().
*/
{
/*
* Validate input.
*/
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
/*
* Close the file and free the handle.
*/
return rc;
}
/**
* Seeks to a specific data unit.
*
* After seeking it's possible to use the getters to on
* that data unit.
*
* @returns VBox status code.
* @returns VERR_SSM_UNIT_NOT_FOUND if the unit+instance wasn't found.
* @param pSSM The SSM handle returned by SSMR3Open().
* @param pszUnit The name of the data unit.
* @param iInstance The instance number.
* @param piVersion Where to store the version number. (Optional)
*/
SSMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion)
{
LogFlow(("SSMR3Seek: pSSM=%p pszUnit=%p:{%s} iInstance=%RU32 piVersion=%p\n",
/*
* Validate input.
*/
AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER);
/*
* Reset the state.
*/
if (pSSM->pZipDecomp)
{
}
pSSM->cbUnitLeft = 0;
/*
* Walk the data units until we find EOF or a match.
*/
int rc = VINF_SUCCESS;
{
/*
* Read the unit header and verify it.
*/
if (VBOX_SUCCESS(rc))
{
{
/*
* Does it match thus far or should we just skip along?
*/
continue;
/*
* Read the name.
* Adjust the name buffer first.
*/
{
if (pszName)
}
rc = VERR_NO_MEMORY;
if (pszName)
{
if (VBOX_SUCCESS(rc))
{
{
/*
* Does the name match? If not continue with the next item.
*/
continue;
if (piVersion)
}
else
{
}
}
}
}
else
{
else
{
AssertMsgFailed(("Invalid unit magic at offset %RTfoff, '%.*s'!\n",
}
}
}
/* error or success, two continue statements cover the iterating */
break;
}
return rc;
}
/**
* Finishes a data unit.
* All buffers and compressor instances are flushed and destroyed.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
*/
{
//Log2(("ssmr3WriteFinish: %#010llx start\n", RTFileTell(pSSM->File)));
return VINF_SUCCESS;
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
{
//Log2(("ssmr3WriteFinish: %#010llx done\n", RTFileTell(pSSM->File)));
return VINF_SUCCESS;
}
}
return rc;
}
/**
* Writes something to the current data item in the saved state file.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pvBuf The bits to write.
* @param cbBuf The number of bytes to write.
*/
{
Log2(("ssmr3Write: pvBuf=%p cbBuf=%#x %.*Vhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
/*
* Check that everything is fine.
*/
{
/*
* First call starts the compression.
*/
{
//int rc = RTZipCompCreate(&pSSM->pZipComp, pSSM, ssmr3WriteOut, RTZIPTYPE_ZLIB, RTZIPLEVEL_FAST);
if (VBOX_FAILURE(rc))
return rc;
}
/*
* Write the data item in 128kb chunks for progress indicator reasons.
*/
while (cbBuf > 0)
{
break;
}
}
}
/**
* Callback for flusing the output buffer of a compression stream.
*
* @returns VBox status.
* @param pvSSM SSM operation handle.
* @param pvBuf Compressed data.
* @param cbBuf Size of the compressed data.
*/
{
//Log2(("ssmr3WriteOut: %#010llx cbBuf=%#x\n", RTFileTell(((PSSMHANDLE)pvSSM)->File), cbBuf));
if (VBOX_SUCCESS(rc))
return rc;
return rc;
}
/**
* Puts a structure.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
* @param pvStruct The structure address.
* @param paFields The array of structure fields descriptions.
* The array must be terminated by a SSMFIELD_ENTRY_TERM().
*/
{
/* begin marker. */
if (VBOX_FAILURE(rc))
return rc;
/* put the fields */
pCur++)
{
if (VBOX_FAILURE(rc))
return rc;
}
/* end marker */
}
/**
* Saves a boolean item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param fBool Item to save.
*/
{
{
}
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 8-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u8 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 8-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i8 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 16-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u16 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 16-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i16 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 32-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u32 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 32-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i32 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 64-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u64 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 64-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i64 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 128-bit unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u128 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a 128-bit signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i128 Item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a VBox unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
{
return ssmr3Write(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a VBox signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
{
return ssmr3Write(pSSM, &i, sizeof(i));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC natural unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
{
return ssmr3Write(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC natural signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
{
return ssmr3Write(pSSM, &i, sizeof(i));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC physical address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPhys The item to save
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC virtual address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPtr The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a GC virtual address (represented as an unsigned integer) item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param GCPtr The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a HC natural unsigned integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param u Item to save.
*/
{
return ssmr3Write(pSSM, &u, sizeof(u));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a HC natural signed integer item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param i Item to save.
*/
{
return ssmr3Write(pSSM, &i, sizeof(i));
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a I/O port address item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param IOPort The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a selector item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param Sel The item to save.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a memory item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pv Item to save.
* @param cb Size of the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Saves a zero terminated string item to the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Item to save.
*/
{
{
{
AssertMsgFailed(("a %d byte long string, what's this!?!\n"));
return VERR_TOO_MUCH_DATA;
}
if (rc)
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Closes the decompressor of a data unit.
*
* @param pSSM SSM operation handle.
*/
{
}
/**
* Internal read worker.
*
* @param pSSM SSM operation handle.
* @param pvBuf Where to store the read data.
* @param cbBuf Number of bytes to read.
*/
{
/*
* Check that everything is fine.
*/
{
/*
* Open the decompressor on the first read.
*/
if (!pSSM->pZipDecomp)
{
}
/*
* Do the requested read.
* Use 32kb chunks to work the progress indicator.
*/
Log2(("ssmr3Read: pvBuf=%p cbBuf=%#x %.*Vhxs%s\n", pvBuf, cbBuf, RT_MIN(cbBuf, 128), pvBuf, cbBuf > 128 ? "..." : ""));
else
}
}
/**
* Callback for reading compressed data into the input buffer of the
* decompressor.
*
* @returns VBox status code.
* @param pvSSM The SSM handle.
* @param pvBuf Where to store the compressed data.
* @param cbBuf Size of the buffer.
* @param pcbRead Number of bytes actually stored in the buffer.
*/
{
if (cbRead)
{
//Log2(("ssmr3ReadIn: %#010llx cbBug=%#x cbRead=%#x\n", RTFileTell(pSSM->File), cbBuf, cbRead));
if (VBOX_SUCCESS(rc))
{
if (pcbRead)
return VINF_SUCCESS;
}
return rc;
}
AssertMsgFailed(("SSM: attempted reading more than the unit!\n"));
return VERR_SSM_LOADED_TOO_MUCH;
}
/**
* Gets a structure.
*
* @returns VBox status code.
* @param pSSM The saved state handle.
* @param pvStruct The structure address.
* @param paFields The array of structure fields descriptions.
* The array must be terminated by a SSMFIELD_ENTRY_TERM().
*/
{
/* begin marker. */
if (VBOX_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_BEGIN)
/* put the fields */
pCur++)
{
if (VBOX_FAILURE(rc))
return rc;
}
/* end marker */
if (VBOX_FAILURE(rc))
return rc;
if (u32Magic != SSMR3STRUCT_END)
return rc;
}
/**
* Loads a boolean item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pfBool Where to store the item.
*/
{
{
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 8-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu8 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 8-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi8 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 16-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu16 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 16-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi16 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 32-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu32 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 32-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi32 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 64-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu64 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 64-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi64 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 128-bit unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu128 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a 128-bit signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi128 Where to store the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a VBox unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a VBox signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC natural unsigned integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pu Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC natural signed integer item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pi Where to store the integer.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC physical address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPhys Where to store the GC physical address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC virtual address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPtr Where to store the GC virtual address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a GC virtual address (represented as unsigned integer) item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pGCPtr Where to store the GC virtual address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a I/O port address item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pIOPort Where to store the I/O port address.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a selector item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pSel Where to store the selector.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a memory item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param pv Where to store the item.
* @param cb Size of the item.
*/
{
return VERR_SSM_INVALID_STATE;
}
/**
* Loads a string item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Where to store the item.
* @param cbMax Max size of the item (including '\\0').
*/
{
}
/**
* Loads a string item from the current data unit.
*
* @returns VBox status.
* @param pSSM SSM operation handle.
* @param psz Where to store the item.
* @param cbMax Max size of the item (including '\\0').
* @param pcbStr The length of the loaded string excluding the '\\0'. (optional)
*/
{
{
/* read size prefix. */
if (VBOX_SUCCESS(rc))
{
if (pcbStr)
{
/* terminate and read string content. */
}
return VERR_TOO_MUCH_DATA;
}
return rc;
}
return VERR_SSM_INVALID_STATE;
}
/**
* Query what the VBox status code of the operation is.
*
* This can be used for putting and getting a batch of values
* without bother checking the result till all the calls have
* been made.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
*/
{
}
/**
* Fail the load operation.
*
* This is mainly intended for sub item loaders (like timers) which
* return code isn't necessarily heeded by the caller but is important
* to SSM.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
* @param iStatus Failure status code. This MUST be a VERR_*.
*/
{
if (VBOX_FAILURE(iStatus))
{
}
return VERR_INVALID_PARAMETER;
}
/**
* Query what to do after this operation.
*
* @returns SSMAFTER enum value.
* @param pSSM SSM operation handle.
*/
{
}