- Timestamp:
- Oct 3, 2024 2:35:14 AM (2 months ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/ssm.h
r106061 r106211 1224 1224 VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, 1225 1225 bool fChecksumIt); 1226 1227 /** Flag for SSMR3Open to create a new file for writing. */ 1228 #define SSM_OPEN_F_FOR_WRITING RT_BIT_32(0) 1226 1229 VMMR3DECL(int) SSMR3Open(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, 1227 u nsignedfFlags, PSSMHANDLE *ppSSM);1230 uint32_t fFlags, PSSMHANDLE *ppSSM); 1228 1231 VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM); 1229 1232 VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion); 1233 VMMR3DECL(int) SSMR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits); 1234 VMMR3DECL(int) SSMR3WriteUnitBegin(PSSMHANDLE pSSM, const char *pszName, uint32_t uVersion, uint32_t uInstance); 1235 VMMR3DECL(int) SSMR3WriteUnitComplete(PSSMHANDLE pSSM); 1236 VMMR3DECL(int) SSMR3WriteFileFooter(PSSMHANDLE pSSM); 1237 1230 1238 VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM); 1231 1239 VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus); -
trunk/src/VBox/VMM/VMMR3/SSM.cpp
r106061 r106211 304 304 #define SSM_ASSERT_WRITEABLE_RET(pSSM) \ 305 305 AssertMsgReturn( pSSM->enmOp == SSMSTATE_SAVE_EXEC \ 306 || pSSM->enmOp == SSMSTATE_LIVE_EXEC,\ 306 || pSSM->enmOp == SSMSTATE_LIVE_EXEC \ 307 || pSSM->enmOp == SSMSTATE_OPEN_WRITE,\ 307 308 ("Invalid state %d\n", pSSM->enmOp), VERR_SSM_INVALID_STATE); 308 309 … … 372 373 SSMSTATE_LOAD_DONE, 373 374 SSMSTATE_OPEN_READ, 375 SSMSTATE_OPEN_WRITE, 374 376 SSMSTATE_END 375 377 } SSMSTATE; … … 526 528 /** The maximum downtime given as milliseconds. */ 527 529 uint32_t cMsMaxDowntime; 530 531 /** SSMSTATE_OPEN_WRITE: Number of allocated directory entries. */ 532 uint32_t cDirEntriesAlloced; 533 /** SSMSTATE_OPEN_WRITE: The directory. */ 534 struct SSMFILEDIR *pDir; 528 535 } Write; 529 536 … … 4735 4742 4736 4743 /** 4737 * Finalize the saved state stream, i.e. add the end unit, directory 4738 * and footer. 4739 * 4740 * @returns VBox status code (pSSM->rc). 4741 * @param pVM The cross context VM structure. 4742 * @param pSSM The saved state handle. 4743 */ 4744 static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM) 4745 { 4746 VM_ASSERT_EMT0(pVM); 4747 Assert(RT_SUCCESS(pSSM->rc)); 4748 4749 /* 4750 * Write the end unit. 4751 */ 4744 * Writes out the END unit. 4745 */ 4746 static int ssmR3WriteEndUnit(PSSMHANDLE pSSM) 4747 { 4748 AssertRC(pSSM->rc); 4752 4749 SSMFILEUNITHDRV2 UnitHdr; 4753 4750 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_END, sizeof(UnitHdr.szMagic)); … … 4766 4763 { 4767 4764 LogRel(("SSM: Failed writing the end unit: %Rrc\n", rc)); 4768 return pSSM->rc = rc; 4769 } 4770 4771 /* 4772 * Write the directory for the final units and then the footer. 4773 */ 4765 pSSM->rc = rc; 4766 } 4767 return rc; 4768 } 4769 4770 4771 /** 4772 * Writes out the file footer and sets the end of the stream. 4773 */ 4774 static int ssmR3WriteFileFooter(PSSMHANDLE pSSM, uint32_t cDirEntries) 4775 { 4774 4776 SSMFILEFTR Footer; 4775 rc = ssmR3WriteDirectory(pVM, pSSM, &Footer.cDirEntries);4776 if (RT_FAILURE(rc))4777 {4778 LogRel(("SSM: Failed writing the directory: %Rrc\n", rc));4779 return pSSM->rc = rc;4780 }4781 4782 4777 memcpy(Footer.szMagic, SSMFILEFTR_MAGIC, sizeof(Footer.szMagic)); 4783 4778 Footer.offStream = ssmR3StrmTell(&pSSM->Strm); 4784 4779 Footer.u32StreamCRC = ssmR3StrmFinalCRC(&pSSM->Strm); 4780 Footer.cDirEntries = cDirEntries; 4785 4781 Footer.u32Reserved = 0; 4786 4782 Footer.u32CRC = 0; 4787 4783 Footer.u32CRC = RTCrc32(&Footer, sizeof(Footer)); 4788 4784 Log(("SSM: Footer at %#9llx: \n", Footer.offStream)); 4789 rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer));4785 int rc = ssmR3StrmWrite(&pSSM->Strm, &Footer, sizeof(Footer)); 4790 4786 if (RT_SUCCESS(rc)) 4791 4787 rc = ssmR3StrmSetEnd(&pSSM->Strm); 4788 if (RT_SUCCESS(rc)) 4789 LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n", Footer.offStream, Footer.offStream, Footer.cDirEntries)); 4790 else 4791 { 4792 LogRel(("SSM: Failed writing the footer: %Rrc\n", rc)); 4793 pSSM->rc = rc; 4794 } 4795 return rc; 4796 } 4797 4798 4799 /** 4800 * Finalize the saved state stream, i.e. add the end unit, directory 4801 * and footer. 4802 * 4803 * @returns VBox status code (pSSM->rc). 4804 * @param pVM The cross context VM structure. 4805 * @param pSSM The saved state handle. 4806 */ 4807 static int ssmR3SaveDoFinalization(PVM pVM, PSSMHANDLE pSSM) 4808 { 4809 VM_ASSERT_EMT0(pVM); 4810 Assert(RT_SUCCESS(pSSM->rc)); 4811 4812 /* 4813 * Write the end unit. 4814 */ 4815 int rc = ssmR3WriteEndUnit(pSSM); 4816 if (RT_SUCCESS(rc)) 4817 { 4818 /* 4819 * Write the directory for the final units and then the footer. 4820 */ 4821 uint32_t cDirEntries = 0; 4822 rc = ssmR3WriteDirectory(pVM, pSSM, &cDirEntries); 4823 if (RT_SUCCESS(rc)) 4824 { 4825 /* 4826 * Write the footer. 4827 */ 4828 rc = ssmR3WriteFileFooter(pSSM, cDirEntries); 4829 } 4830 else 4831 { 4832 LogRel(("SSM: Failed writing the directory: %Rrc\n", rc)); 4833 pSSM->rc = rc; 4834 } 4835 } 4836 return rc; 4837 } 4838 4839 4840 /** 4841 * Writes the file directory and footer. 4842 * 4843 * @returns VBox status code. 4844 * @param pSSM The SSM handle. 4845 */ 4846 VMMR3DECL(int) SSMR3WriteFileFooter(PSSMHANDLE pSSM) 4847 { 4848 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 4849 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 4850 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER); 4851 Assert(pSSM->fCancelled == SSMHANDLE_OK); 4852 4853 /* 4854 * Write the directory. 4855 */ 4856 PSSMFILEDIR pDir = pSSM->u.Write.pDir; 4857 if (!pDir) 4858 { 4859 /* Allocate an empty directory as a placeholder. (Don't know we can 4860 read this back, but whatever) */ 4861 pSSM->u.Write.pDir = pDir = (PSSMFILEDIR)RTMemAllocZ(RT_UOFFSETOF(SSMFILEDIR, aEntries[1])); 4862 AssertReturn(pDir, VERR_NO_MEMORY); 4863 pSSM->u.Write.cDirEntriesAlloced = 1; 4864 } 4865 memcpy(pDir->szMagic, SSMFILEDIR_MAGIC, sizeof(pDir->szMagic)); 4866 pDir->u32CRC = 0; 4867 uint32_t const cbDir = RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[pDir->cEntries]); 4868 pDir->u32CRC = RTCrc32(pDir, cbDir); 4869 int rc = ssmR3StrmWrite(&pSSM->Strm, pDir, cbDir); 4792 4870 if (RT_FAILURE(rc)) 4793 { 4794 LogRel(("SSM: Failed writing the footer: %Rrc\n", rc)); 4795 return pSSM->rc = rc; 4796 } 4797 4798 LogRel(("SSM: Footer at %#llx (%lld), %u directory entries.\n", 4799 Footer.offStream, Footer.offStream, Footer.cDirEntries)); 4800 return VINF_SUCCESS; 4871 return rc; 4872 4873 /* 4874 * Write the footer. 4875 */ 4876 return ssmR3WriteFileFooter(pSSM, pDir->cEntries); 4801 4877 } 4802 4878 … … 4823 4899 } 4824 4900 } 4901 } 4902 4903 4904 /** 4905 * Head code for saving a unit shared by ssmR3SaveDoExecRun() and 4906 * SSMR3WriteUnitBegin(). 4907 */ 4908 static int ssmR3SaveDoExecRunOneUnitBegin(PSSMHANDLE pSSM, PSSMUNIT pUnit, unsigned iUnit) 4909 { 4910 /* 4911 * Not all unit have a callback. Skip those which don't and 4912 * make sure to keep the progress indicator up to date. 4913 */ 4914 ssmR3ProgressByUnit(pSSM, iUnit); 4915 pSSM->offEstUnitEnd += pUnit->cbGuess; 4916 if (!pUnit->u.Common.pfnSaveExec) 4917 { 4918 pUnit->fCalled = true; 4919 if (pUnit->cbGuess) 4920 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 4921 return VINF_NO_CHANGE; 4922 } 4923 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm); 4924 4925 /* 4926 * Check for cancellation. 4927 */ 4928 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED)) 4929 { 4930 LogRel(("SSM: Cancelled!\n")); 4931 AssertRC(pSSM->rc); 4932 return pSSM->rc = VERR_SSM_CANCELLED; 4933 } 4934 4935 /* 4936 * Write data unit header 4937 */ 4938 SSMFILEUNITHDRV2 UnitHdr; 4939 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)); 4940 UnitHdr.offStream = pUnit->offStream; 4941 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm); 4942 UnitHdr.u32CRC = 0; 4943 UnitHdr.u32Version = pUnit->u32Version; 4944 UnitHdr.u32Instance = pUnit->u32Instance; 4945 UnitHdr.u32Pass = SSM_PASS_FINAL; 4946 UnitHdr.fFlags = 0; 4947 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1; 4948 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName); 4949 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 4950 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n", 4951 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version)); 4952 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 4953 if (RT_FAILURE(rc)) 4954 { 4955 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc)); 4956 return pSSM->rc = rc; 4957 } 4958 4959 ssmR3DataWriteBegin(pSSM); 4960 return VINF_SUCCESS; 4961 } 4962 4963 4964 /** 4965 * Tail code for saving a unit shared by ssmR3SaveDoExecRun() and 4966 * SSMR3WriteUnitComplete(). 4967 */ 4968 static int ssmR3SaveDoExecRunOneUnitComplete(PSSMHANDLE pSSM) 4969 { 4970 /* 4971 * Write the termination record and flush the compression stream. 4972 */ 4973 SSMRECTERM TermRec; 4974 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM; 4975 TermRec.cbRec = sizeof(TermRec) - 2; 4976 if (pSSM->Strm.fChecksummed) 4977 { 4978 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32; 4979 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2)); 4980 } 4981 else 4982 { 4983 TermRec.fFlags = 0; 4984 TermRec.u32StreamCRC = 0; 4985 } 4986 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec); 4987 int rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec)); 4988 if (RT_SUCCESS(rc)) 4989 rc = ssmR3DataWriteFinish(pSSM); 4990 if (RT_FAILURE(rc)) 4991 { 4992 LogRel(("SSM: Failed terminating unit: %Rrc\n", rc)); 4993 return pSSM->rc = rc; 4994 } 4995 4996 /* 4997 * Advance the progress indicator to the end of the current unit. 4998 */ 4999 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 5000 5001 return VINF_SUCCESS; 4825 5002 } 4826 5003 … … 4843 5020 { 4844 5021 /* 4845 * Not all unit have a callback. Skip those which don't and 4846 * make sure to keep the progress indicator up to date. 5022 * Begin unit saving. 4847 5023 */ 4848 ssmR3ProgressByUnit(pSSM, iUnit); 4849 pSSM->offEstUnitEnd += pUnit->cbGuess; 4850 if (!pUnit->u.Common.pfnSaveExec) 4851 { 4852 pUnit->fCalled = true; 4853 if (pUnit->cbGuess) 4854 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 4855 continue; 4856 } 4857 pUnit->offStream = ssmR3StrmTell(&pSSM->Strm); 4858 4859 /* 4860 * Check for cancellation. 4861 */ 4862 if (RT_UNLIKELY(ASMAtomicUoReadU32(&(pSSM)->fCancelled) == SSMHANDLE_CANCELLED)) 4863 { 4864 LogRel(("SSM: Cancelled!\n")); 4865 AssertRC(pSSM->rc); 4866 return pSSM->rc = VERR_SSM_CANCELLED; 4867 } 4868 4869 /* 4870 * Write data unit header 4871 */ 4872 SSMFILEUNITHDRV2 UnitHdr; 4873 memcpy(&UnitHdr.szMagic[0], SSMFILEUNITHDR_MAGIC, sizeof(UnitHdr.szMagic)); 4874 UnitHdr.offStream = pUnit->offStream; 4875 UnitHdr.u32CurStreamCRC = ssmR3StrmCurCRC(&pSSM->Strm); 4876 UnitHdr.u32CRC = 0; 4877 UnitHdr.u32Version = pUnit->u32Version; 4878 UnitHdr.u32Instance = pUnit->u32Instance; 4879 UnitHdr.u32Pass = SSM_PASS_FINAL; 4880 UnitHdr.fFlags = 0; 4881 UnitHdr.cbName = (uint32_t)pUnit->cchName + 1; 4882 memcpy(&UnitHdr.szName[0], &pUnit->szName[0], UnitHdr.cbName); 4883 UnitHdr.u32CRC = RTCrc32(&UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 4884 Log(("SSM: Unit at %#9llx: '%s', instance %u, pass %#x, version %u\n", 4885 UnitHdr.offStream, UnitHdr.szName, UnitHdr.u32Instance, UnitHdr.u32Pass, UnitHdr.u32Version)); 4886 int rc = ssmR3StrmWrite(&pSSM->Strm, &UnitHdr, RT_UOFFSETOF_DYN(SSMFILEUNITHDRV2, szName[UnitHdr.cbName])); 4887 if (RT_FAILURE(rc)) 4888 { 4889 LogRel(("SSM: Failed to write unit header. rc=%Rrc\n", rc)); 4890 return pSSM->rc = rc; 5024 int rc = ssmR3SaveDoExecRunOneUnitBegin(pSSM, pUnit, iUnit); 5025 if (rc != VINF_SUCCESS) 5026 { 5027 Assert(RT_FAILURE_NP(rc) || (!pUnit->u.Common.pfnSaveExec && rc == VINF_NO_CHANGE)); 5028 if (RT_SUCCESS(rc)) 5029 continue; 5030 return rc; 4891 5031 } 4892 5032 … … 4894 5034 * Call the execute handler. 4895 5035 */ 4896 ssmR3DataWriteBegin(pSSM);4897 5036 ssmR3UnitCritSectEnter(pVM, pUnit); 4898 5037 switch (pUnit->enmType) … … 4930 5069 4931 5070 /* 4932 * Write the termination record and flush the compression stream.5071 * Finish the unit. 4933 5072 */ 4934 SSMRECTERM TermRec; 4935 TermRec.u8TypeAndFlags = SSM_REC_FLAGS_FIXED | SSM_REC_FLAGS_IMPORTANT | SSM_REC_TYPE_TERM; 4936 TermRec.cbRec = sizeof(TermRec) - 2; 4937 if (pSSM->Strm.fChecksummed) 4938 { 4939 TermRec.fFlags = SSMRECTERM_FLAGS_CRC32; 4940 TermRec.u32StreamCRC = RTCrc32Finish(RTCrc32Process(ssmR3StrmCurCRC(&pSSM->Strm), &TermRec, 2)); 4941 } 4942 else 4943 { 4944 TermRec.fFlags = 0; 4945 TermRec.u32StreamCRC = 0; 4946 } 4947 TermRec.cbUnit = pSSM->offUnit + sizeof(TermRec); 4948 rc = ssmR3DataWriteRaw(pSSM, &TermRec, sizeof(TermRec)); 4949 if (RT_SUCCESS(rc)) 4950 rc = ssmR3DataWriteFinish(pSSM); 5073 rc = ssmR3SaveDoExecRunOneUnitComplete(pSSM); 4951 5074 if (RT_FAILURE(rc)) 4952 5075 { 4953 LogRel(("SSM: Failed terminating unit: %Rrc\n", rc)); 4954 return pSSM->rc = rc; 4955 } 4956 4957 /* 4958 * Advance the progress indicator to the end of the current unit. 4959 */ 4960 ssmR3ProgressByByte(pSSM, pSSM->offEstUnitEnd - pSSM->offEst); 5076 Assert(RT_FAILURE_NP(pSSM->rc)); 5077 return rc; 5078 } 4961 5079 } /* for each unit */ 4962 5080 ssmR3ProgressByUnit(pSSM, pVM->ssm.s.cUnits); … … 4967 5085 ("%d\n", pSSM->uPercent)); 4968 5086 return VINF_SUCCESS; 5087 } 5088 5089 5090 /** 5091 * Begins saving a unit to a SSM file/stream opened via SSMR3Open. 5092 * 5093 * @returns VBox status code. 5094 * @param pSSM The saved state handle. 5095 * @param pszName The unit name. 5096 * @param uVersion The unit version. 5097 * @param uInstance The unit instance number. 5098 */ 5099 VMMR3DECL(int) SSMR3WriteUnitBegin(PSSMHANDLE pSSM, const char *pszName, uint32_t uVersion, uint32_t uInstance) 5100 { 5101 /* 5102 * Validate input and state. 5103 */ 5104 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 5105 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 5106 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER); 5107 5108 AssertPtrReturn(pszName, VERR_INVALID_PARAMETER); 5109 size_t const cchName = strlen(pszName); 5110 AssertReturn(cchName > 0 && cchName < SSM_MAX_NAME_SIZE, VERR_INVALID_NAME); 5111 5112 5113 /* 5114 * We abuse u32CRC to indicate whether we've started a unit. 5115 */ 5116 AssertRCReturn(pSSM->rc, pSSM->rc); 5117 AssertReturn(!pSSM->u.Write.pDir || pSSM->u.Write.pDir->u32CRC == 0, pSSM->rc = VERR_INVALID_STATE); 5118 5119 /* 5120 * Add the unit to the directory. 5121 */ 5122 PSSMFILEDIR pDir = pSSM->u.Write.pDir; 5123 uint32_t cAlloced = pSSM->u.Write.cDirEntriesAlloced; 5124 if (!pDir || pDir->cEntries + 1 > cAlloced) 5125 { 5126 pDir = (PSSMFILEDIR)RTMemReallocZ(pDir, cAlloced ? RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[cAlloced]) : 0, 5127 RT_UOFFSETOF_DYN(SSMFILEDIR, aEntries[cAlloced + 16])); 5128 AssertReturn(pDir, pSSM->rc = VERR_NO_MEMORY); 5129 pSSM->u.Write.cDirEntriesAlloced = cAlloced + 16; 5130 pSSM->u.Write.pDir = pDir; 5131 } 5132 pDir->aEntries[pDir->cEntries].off = ssmR3StrmTell(&pSSM->Strm); 5133 pDir->aEntries[pDir->cEntries].u32Instance = uInstance; 5134 pDir->aEntries[pDir->cEntries].u32NameCRC = RTCrc32(pszName, cchName); 5135 pDir->cEntries++; 5136 5137 /* 5138 * Create a unit structure and join paths with ssmR3SaveDoExecRun. 5139 */ 5140 union 5141 { 5142 SSMUNIT Unit; 5143 uint8_t abPadding[RT_UOFFSETOF(SSMUNIT, szName) + SSM_MAX_NAME_SIZE]; 5144 } u; 5145 RT_ZERO(u); 5146 u.Unit.enmType = SSMUNITTYPE_EXTERNAL; 5147 u.Unit.u32Version = uVersion; 5148 u.Unit.u32Instance = uInstance; 5149 u.Unit.offStream = 0; 5150 u.Unit.pCritSect = NULL; 5151 u.Unit.u.Common.pfnSaveExec = (PFNRT)~(uintptr_t)1; /* must be non-zero */ 5152 u.Unit.cbGuess = 64; /* whatever */ 5153 u.Unit.cchName = cchName; 5154 memcpy(u.Unit.szName, pszName, cchName + 1); 5155 5156 int rc = ssmR3SaveDoExecRunOneUnitBegin(pSSM, &u.Unit, pDir->cEntries - 1); 5157 if (rc == VINF_SUCCESS) 5158 pSSM->u.Write.pDir->u32CRC = 1; /* See above. */ 5159 else 5160 Assert(RT_FAILURE_NP(rc)); 5161 return rc; 5162 } 5163 5164 5165 /** 5166 * Completes a unit started by SSMR3WriteUnitBegin(). 5167 * 5168 * @returns VBox status code. 5169 * @param pSSM The saved state handle. 5170 */ 5171 VMMR3DECL(int) SSMR3WriteUnitComplete(PSSMHANDLE pSSM) 5172 { 5173 /* 5174 * Validate input and state. 5175 */ 5176 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 5177 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 5178 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER); 5179 5180 AssertReturn(pSSM->u.Write.pDir, VERR_INVALID_STATE); 5181 AssertReturn(pSSM->u.Write.pDir->cEntries > 0, VERR_INVALID_STATE); 5182 AssertReturn(pSSM->u.Write.pDir->u32CRC == 1, VERR_INVALID_STATE); 5183 5184 AssertRCReturn(pSSM->rc, pSSM->rc); 5185 pSSM->u.Write.pDir->u32CRC = 0; 5186 5187 /* 5188 * Finish the unit. 5189 */ 5190 int rc = ssmR3DataFlushBuffer(pSSM); /* will return SSMHANDLE::rc if it is set */ 5191 if (RT_SUCCESS(rc)) 5192 rc = ssmR3SaveDoExecRunOneUnitComplete(pSSM); 5193 return rc; 4969 5194 } 4970 5195 … … 5104 5329 5105 5330 /** 5106 * Writes the file header and clear the per-unit data. 5107 * 5108 * @returns VBox status code. 5109 * @param pVM The cross context VM structure. 5331 * Writes the file header. 5332 * 5333 * @returns VBox status code. 5110 5334 * @param pSSM The SSM handle. 5111 */ 5112 static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM) 5113 { 5114 /* 5115 * Write the header. 5116 */ 5335 * @param cUnits Copy of pVM->ssm.s.cUnits, typically. 5336 */ 5337 static int ssmR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits) 5338 { 5117 5339 SSMFILEHDR FileHdr; 5118 5340 memcpy(&FileHdr.szMagic, SSMFILEHDR_MAGIC_V2_0, sizeof(FileHdr.szMagic)); … … 5125 5347 FileHdr.cbGCPtr = sizeof(RTGCPTR); 5126 5348 FileHdr.u8Reserved = 0; 5127 FileHdr.cUnits = pVM->ssm.s.cUnits;5349 FileHdr.cUnits = cUnits; 5128 5350 FileHdr.fFlags = SSMFILEHDR_FLAGS_STREAM_CRC32; 5129 5351 if (pSSM->fLiveSave) … … 5132 5354 FileHdr.u32CRC = 0; 5133 5355 FileHdr.u32CRC = RTCrc32(&FileHdr, sizeof(FileHdr)); 5134 int rc = ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr)); 5135 if (RT_FAILURE(rc)) 5136 return rc; 5137 5138 /* 5139 * Clear the per unit flags and offsets. 5140 */ 5141 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 5142 { 5143 pUnit->fCalled = false; 5144 pUnit->offStream = RTFOFF_MIN; 5145 } 5146 5147 return VINF_SUCCESS; 5356 return ssmR3StrmWrite(&pSSM->Strm, &FileHdr, sizeof(FileHdr)); 5357 } 5358 5359 5360 /** 5361 * Writes the file header. 5362 * 5363 * @returns VBox status code. 5364 * @param pSSM The SSM handle. 5365 * @param cUnits Number of units to advertise in the header. 5366 */ 5367 VMMR3DECL(int) SSMR3WriteFileHeader(PSSMHANDLE pSSM, uint32_t cUnits) 5368 { 5369 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 5370 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_WRITE, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 5371 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER); 5372 AssertMsgReturn(cUnits > 0 && cUnits < _4K, ("%d\n", cUnits),VERR_INVALID_PARAMETER); 5373 Assert(pSSM->fCancelled == SSMHANDLE_OK); 5374 5375 return ssmR3WriteFileHeader(pSSM, cUnits); 5376 } 5377 5378 5379 /** 5380 * Writes the file header and clear the per-unit data. 5381 * 5382 * @returns VBox status code. 5383 * @param pVM The cross context VM structure. 5384 * @param pSSM The SSM handle. 5385 */ 5386 static int ssmR3WriteHeaderAndClearPerUnitData(PVM pVM, PSSMHANDLE pSSM) 5387 { 5388 /* 5389 * Write the header. 5390 */ 5391 int rc = ssmR3WriteFileHeader(pSSM, pVM->ssm.s.cUnits); 5392 if (RT_SUCCESS(rc)) 5393 { 5394 /* 5395 * Clear the per unit flags and offsets. 5396 */ 5397 for (PSSMUNIT pUnit = pVM->ssm.s.pHead; pUnit; pUnit = pUnit->pNext) 5398 { 5399 pUnit->fCalled = false; 5400 pUnit->offStream = RTFOFF_MIN; 5401 } 5402 } 5403 return rc; 5148 5404 } 5149 5405 … … 9370 9626 * used. 9371 9627 * @param pvStreamOps The user argument to the stream methods. 9372 * @param fFlags Open flags . Reserved, must be 0.9628 * @param fFlags Open flags, SSM_OPEN_F_XXXX. 9373 9629 * @param ppSSM Where to store the SSM handle. 9374 9630 * … … 9384 9640 */ 9385 9641 AssertReturn(!pszFilename != !pStreamOps, VERR_INVALID_POINTER); 9386 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_PARAMETER); 9642 #ifndef SSM_STANDALONE 9643 AssertMsgReturn(!(fFlags & ~SSM_OPEN_F_FOR_WRITING), ("%#x\n", fFlags), VERR_INVALID_FLAGS); 9644 #else 9645 AssertMsgReturn(!fFlags, ("%#x\n", fFlags), VERR_INVALID_FLAGS); 9646 #endif 9387 9647 AssertPtrReturn(ppSSM, VERR_INVALID_POINTER); 9388 9648 9389 /* 9390 * Allocate a handle. 9391 */ 9392 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM)); 9393 AssertReturn(pSSM, VERR_NO_MEMORY); 9394 9395 /* 9396 * Try open the file and validate it. 9397 */ 9398 int rc = ssmR3OpenFile(NULL, pszFilename, pStreamOps, pvStreamOps, false /*fChecksumIt*/, 9399 true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM); 9400 if (RT_SUCCESS(rc)) 9401 { 9402 pSSM->enmAfter = SSMAFTER_OPENED; 9403 pSSM->enmOp = SSMSTATE_OPEN_READ; 9404 *ppSSM = pSSM; 9405 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM)); 9406 return VINF_SUCCESS; 9407 } 9408 9409 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc)); 9410 RTMemFree(pSSM); 9649 int rc; 9650 #ifndef SSM_STANDALONE 9651 if (fFlags & SSM_OPEN_F_FOR_WRITING) 9652 { 9653 /* 9654 * Try create a new file. 9655 */ 9656 PSSMHANDLE pSSM; 9657 rc = ssmR3SaveDoCreateFile(NULL, pszFilename, pStreamOps, pvStreamOps, SSMAFTER_OPENED, NULL, NULL, &pSSM); 9658 if (RT_SUCCESS(rc)) 9659 { 9660 Log(("SSM: Starting state save to file '%s'...\n", pszFilename)); 9661 ssmR3StrmStartIoThread(&pSSM->Strm); 9662 pSSM->enmOp = SSMSTATE_OPEN_WRITE; 9663 *ppSSM = pSSM; 9664 return VINF_SUCCESS; 9665 } 9666 Log(("SSMR3Open: Failed to open saved state file '%s' for writing: rc=%Rrc.\n", pszFilename, rc)); 9667 } 9668 else 9669 #endif /* !SSM_STANDALONE */ 9670 { 9671 /* 9672 * Allocate a handle. 9673 */ 9674 PSSMHANDLE pSSM = (PSSMHANDLE)RTMemAllocZ(sizeof(*pSSM)); 9675 AssertReturn(pSSM, VERR_NO_MEMORY); 9676 9677 /* 9678 * Try open the file and validate the header and stuff. 9679 */ 9680 rc = ssmR3OpenFile(NULL, pszFilename, pStreamOps, pvStreamOps, false /*fChecksumIt*/, 9681 true /*fChecksumOnRead*/, 1 /*cBuffers*/, pSSM); 9682 if (RT_SUCCESS(rc)) 9683 { 9684 pSSM->enmAfter = SSMAFTER_OPENED; 9685 pSSM->enmOp = SSMSTATE_OPEN_READ; 9686 *ppSSM = pSSM; 9687 LogFlow(("SSMR3Open: returns VINF_SUCCESS *ppSSM=%p\n", *ppSSM)); 9688 return VINF_SUCCESS; 9689 } 9690 9691 Log(("SSMR3Open: Failed to open saved state file '%s', rc=%Rrc.\n", pszFilename, rc)); 9692 RTMemFree(pSSM); 9693 } 9694 9411 9695 return rc; 9412 9413 9696 } 9414 9697 … … 9432 9715 AssertPtrReturn(pSSM, VERR_INVALID_POINTER); 9433 9716 AssertMsgReturn(pSSM->enmAfter == SSMAFTER_OPENED, ("%d\n", pSSM->enmAfter),VERR_INVALID_PARAMETER); 9434 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ, ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 9717 AssertMsgReturn(pSSM->enmOp == SSMSTATE_OPEN_READ || pSSM->enmOp == SSMSTATE_OPEN_WRITE, 9718 ("%d\n", pSSM->enmOp), VERR_INVALID_PARAMETER); 9435 9719 Assert(pSSM->fCancelled == SSMHANDLE_OK); 9436 9720 … … 9439 9723 */ 9440 9724 int rc = ssmR3StrmClose(&pSSM->Strm, pSSM->rc == VERR_SSM_CANCELLED); 9441 if (pSSM-> u.Read.pZipDecompV1)9725 if (pSSM->enmOp == SSMSTATE_OPEN_READ && pSSM->u.Read.pZipDecompV1) 9442 9726 { 9443 9727 RTZipDecompDestroy(pSSM->u.Read.pZipDecompV1); 9444 9728 pSSM->u.Read.pZipDecompV1 = NULL; 9729 } 9730 if (pSSM->enmOp == SSMSTATE_OPEN_WRITE && pSSM->u.Write.pDir) 9731 { 9732 RTMemFree(pSSM->u.Write.pDir); 9733 pSSM->u.Write.pDir = NULL; 9445 9734 } 9446 9735 RTMemFree(pSSM);
Note:
See TracChangeset
for help on using the changeset viewer.