DECLHIDDEN(int) drvHostBaseGetMediaSizeOs(PDRVHOSTBASE pThis, uint64_t *pcb) { int rc = VERR_INVALID_STATE; if (PDMMEDIATYPE_IS_FLOPPY(pThis->enmType)) { rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDFLUSH); if (rc) { rc = RTErrConvertFromErrno (errno); Log(("DrvHostFloppy: FDFLUSH ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc)); return rc; } floppy_drive_struct DrvStat; rc = ioctl(RTFileToNative(pThis->Os.hFileDevice), FDGETDRVSTAT, &DrvStat); if (rc) { rc = RTErrConvertFromErrno(errno); Log(("DrvHostFloppy: FDGETDRVSTAT ioctl(%s) failed, errno=%d rc=%Rrc\n", pThis->pszDevice, errno, rc)); return rc; } pThis->fReadOnly = !(DrvStat.flags & FD_DISK_WRITABLE); rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb); } else if (pThis->enmType == PDMMEDIATYPE_CDROM || pThis->enmType == PDMMEDIATYPE_DVD) { /* Clear the media-changed-since-last-call-thingy just to be on the safe side. */ ioctl(RTFileToNative(pThis->Os.hFileDevice), CDROM_MEDIA_CHANGED, CDSL_CURRENT); rc = RTFileSeek(pThis->Os.hFileDevice, 0, RTFILE_SEEK_END, pcb); } return rc; }
int Ebml_WriteWebMFileFooter(EbmlGlobal *glob, long hash) { int rc = VINF_SUCCESS; if (glob->cluster_open) rc = ebml_EndSubElement(glob, glob->startCluster); { uint64_t start; glob->cue_pos = RTFileTell(glob->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &start, Cues); for (unsigned i = 0; i < glob->cues; i++) { struct cue_entry *cue = &glob->cue_list[i]; uint64_t startSub; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &startSub, CuePoint); { uint64_t startSubsub; if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, CueTime, cue->time); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &startSubsub, CueTrackPositions); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, CueTrack, 1); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned64(glob, CueClusterPosition, cue->loc - glob->position_reference); //Ebml_SerializeUnsigned(glob, CueBlockNumber, cue->blockNumber); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, startSubsub); } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, startSub); } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, start); } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, glob->startSegment); /* Patch up the seek info block */ if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekInfo(glob); /* Patch up the track id */ if (RT_SUCCESS(rc)) rc = RTFileSeek(glob->file, glob->track_id_pos, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) rc = ebml_SerializeUnsigned32(glob, TrackUID, glob->debug ? 0xDEADBEEF : hash); if (RT_SUCCESS(rc)) rc = RTFileSeek(glob->file, 0, RTFILE_SEEK_END, NULL); return rc; }
/** * Read bytes from a file at a given offset. * This function may modify the file position. * * @returns iprt status code. * @param File Handle to the file. * @param off Where to read. * @param pvBuf Where to put the bytes we read. * @param cbToRead How much to read. * @param *pcbRead How much we actually read. * If NULL an error will be returned for a partial read. */ RTR3DECL(int) RTFileReadAt(RTFILE File, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead) { int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) rc = RTFileRead(File, pvBuf, cbToRead, pcbRead); return rc; }
/** @copydoc KRDROPS::pfnRead */ static int krdrRTFileRead(PKRDR pRdr, void *pvBuf, KSIZE cb, KFOFF off) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; int rc; /* * Do a seek if needed. */ if (pRdrFile->off != off) { rc = RTFileSeek(pRdrFile->File, off, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { pRdrFile->off = -1; return rc; } } /* * Do the read. */ rc = RTFileRead(pRdrFile->File, pvBuf, cb, NULL); if (RT_FAILURE(rc)) { pRdrFile->off = -1; return rc; } pRdrFile->off = off + cb; return 0; }
/** * Write bytes to a file at a given offset. * This function may modify the file position. * * @returns iprt status code. * @param File Handle to the file. * @param off Where to write. * @param pvBuf What to write. * @param cbToWrite How much to write. * @param *pcbWritten How much we actually wrote. * If NULL an error will be returned for a partial write. */ RTR3DECL(int) RTFileWriteAt(RTFILE File, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten) { int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) rc = RTFileWrite(File, pvBuf, cbToWrite, pcbWritten); return rc; }
static int ebml_EndSubElement(EbmlGlobal *glob, uint64_t ebmlLoc) { /* Save the current file pointer */ uint64_t pos = RTFileTell(glob->file); /* Calculate the size of this element */ uint64_t size = pos - ebmlLoc - 8; size |= UINT64_C(0x0100000000000000); /* Seek back to the beginning of the element and write the new size */ RTFileSeek(glob->file, ebmlLoc, RTFILE_SEEK_BEGIN, NULL); int rc = ebml_WriteU64(glob, RT_H2BE_U64(size)); /* Reset the file pointer */ RTFileSeek(glob->file, pos, RTFILE_SEEK_BEGIN, NULL); return rc; }
uint64_t File::pos() const { uint64_t p = 0; int vrc = RTFileSeek(m->handle, 0, RTFILE_SEEK_CURRENT, &p); if (RT_SUCCESS(vrc)) return p; throw EIPRTFailure(vrc, "Runtime error seeking in file '%s'", m->strFileName.c_str()); }
void File::setPos(uint64_t aPos) { uint64_t p = 0; unsigned method = RTFILE_SEEK_BEGIN; int vrc = VINF_SUCCESS; /* check if we overflow int64_t and move to INT64_MAX first */ if ((int64_t)aPos < 0) { vrc = RTFileSeek(m->handle, INT64_MAX, method, &p); aPos -= (uint64_t)INT64_MAX; method = RTFILE_SEEK_CURRENT; } /* seek the rest */ if (RT_SUCCESS(vrc)) vrc = RTFileSeek(m->handle, (int64_t) aPos, method, &p); if (RT_SUCCESS(vrc)) return; throw EIPRTFailure(vrc, "Runtime error seeking in file '%s'", m->strFileName.c_str()); }
/** * Gets the current file position. * * @returns File offset. * @returns ~0UUL on failure. * @param File File handle. */ RTR3DECL(uint64_t) RTFileTell(RTFILE File) { /* * Call the seek api to query the stuff. */ uint64_t off = 0; int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, &off); if (RT_SUCCESS(rc)) return off; AssertMsgFailed(("RTFileSeek(%d) -> %d\n", File, rc)); return ~0ULL; }
int Ebml_WriteWebMSeekInfo(EbmlGlobal *ebml) { int rc = VINF_SUCCESS; /* Save the current file pointer */ uint64_t pos = RTFileTell(ebml->file); if (ebml->seek_info_pos) rc = RTFileSeek(ebml->file, ebml->seek_info_pos, RTFILE_SEEK_BEGIN, NULL); else ebml->seek_info_pos = pos; { uint64_t start; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(ebml, &start, SeekHead); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Tracks, ebml->track_pos); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Cues, ebml->cue_pos); if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekElement(ebml, Info, ebml->segment_info_pos); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(ebml, start); } { //segment info uint64_t startInfo; uint64_t frame_time; frame_time = (uint64_t)1000 * ebml->framerate.den / ebml->framerate.num; ebml->segment_info_pos = RTFileTell(ebml->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(ebml, &startInfo, Info); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(ebml, TimecodeScale, 1000000); if (RT_SUCCESS(rc)) rc = Ebml_SerializeFloat(ebml, Segment_Duration, (double)(ebml->last_pts_ms + frame_time)); char szVersion[64]; RTStrPrintf(szVersion, sizeof(szVersion), "vpxenc%", ebml->debug ? vpx_codec_version_str() : ""); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(ebml, MuxingApp, szVersion); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(ebml, WritingApp, szVersion); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(ebml, startInfo); } return rc; }
DECLINLINE(int) tftpReadDataBlock(PNATState pData, PTFTPSESSION pcTftpSession, uint8_t *pu8Data, int *pcbReadData) { RTFILE hSessionFile; int rc = VINF_SUCCESS; uint16_t u16BlkSize = 0; AssertPtrReturn(pData, VERR_INVALID_PARAMETER); AssertPtrReturn(pcTftpSession, VERR_INVALID_PARAMETER); AssertPtrReturn(pu8Data, VERR_INVALID_PARAMETER); AssertPtrReturn(pcbReadData, VERR_INVALID_PARAMETER); AssertReturn(pcTftpSession->OptionBlkSize.u64Value < UINT16_MAX, VERR_INVALID_PARAMETER); LogFlowFunc(("pcTftpSession:%p, pu8Data:%p, pcbReadData:%p\n", pcTftpSession, pu8Data, pcbReadData)); u16BlkSize = (uint16_t)pcTftpSession->OptionBlkSize.u64Value; rc = pftpSessionOpenFile(pData, pcTftpSession, &hSessionFile); if (RT_FAILURE(rc)) { LogFlowFuncLeaveRC(rc); return rc; } if (pcbReadData) { rc = RTFileSeek(hSessionFile, pcTftpSession->cbTransfered, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTFileClose(hSessionFile); LogFlowFuncLeaveRC(rc); return rc; } rc = RTFileRead(hSessionFile, pu8Data, u16BlkSize, (size_t *)pcbReadData); if (RT_FAILURE(rc)) { RTFileClose(hSessionFile); LogFlowFuncLeaveRC(rc); return rc; } } rc = RTFileClose(hSessionFile); LogFlowFuncLeaveRC(rc); return rc; }
static DECLCALLBACK(int) loadMem(PVM pVM, RTFILE File, uint64_t *poff) { uint64_t off = *poff; RTPrintf("info: loading memory...\n"); int rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) { RTGCPHYS GCPhys = 0; for (;;) { if (!(GCPhys % (PAGE_SIZE * 0x1000))) RTPrintf("info: %RGp...\n", GCPhys); /* read a page from the file */ size_t cbRead = 0; uint8_t au8Page[PAGE_SIZE * 16]; rc = RTFileRead(File, &au8Page, sizeof(au8Page), &cbRead); if (RT_SUCCESS(rc) && !cbRead) rc = RTFileRead(File, &au8Page, sizeof(au8Page), &cbRead); if (RT_SUCCESS(rc) && !cbRead) rc = VERR_EOF; if (RT_FAILURE(rc) || rc == VINF_EOF) { if (rc == VERR_EOF) rc = VINF_SUCCESS; else RTPrintf("error: Read error %Rrc while reading the raw memory file.\n", rc); break; } /* Write that page to the guest - skip known rom areas for now. */ if (GCPhys < 0xa0000 || GCPhys >= 0x10000) /* ASSUME size of a8Page is a power of 2. */ PGMPhysWrite(pVM, GCPhys, &au8Page, cbRead); GCPhys += cbRead; } } else RTPrintf("error: Failed to seek to 0x%llx in the raw memory file. rc=%Rrc\n", off, rc); return rc; }
/** * Get the size of the given file. * Works for block devices too. * * @returns VBox status code. * @param hFile The file handle. * @param pcbSize Where to store the size of the file on success. */ static int pdmacFileEpNativeGetSize(RTFILE hFile, uint64_t *pcbSize) { int rc = VINF_SUCCESS; uint64_t cbSize = 0; rc = RTFileGetSize(hFile, &cbSize); if (RT_SUCCESS(rc) && (cbSize != 0)) *pcbSize = cbSize; else { #ifdef RT_OS_WINDOWS DISK_GEOMETRY DriveGeo; DWORD cbDriveGeo; if (DeviceIoControl((HANDLE)RTFileToNative(hFile), IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL)) { if ( DriveGeo.MediaType == FixedMedia || DriveGeo.MediaType == RemovableMedia) { cbSize = DriveGeo.Cylinders.QuadPart * DriveGeo.TracksPerCylinder * DriveGeo.SectorsPerTrack * DriveGeo.BytesPerSector; GET_LENGTH_INFORMATION DiskLenInfo; DWORD junk; if (DeviceIoControl((HANDLE)RTFileToNative(hFile), IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &DiskLenInfo, sizeof(DiskLenInfo), &junk, (LPOVERLAPPED)NULL)) { /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */ cbSize = DiskLenInfo.Length.QuadPart; } rc = VINF_SUCCESS; } else { rc = VERR_INVALID_PARAMETER; } } else rc = RTErrConvertFromWin32(GetLastError()); #elif defined(RT_OS_DARWIN) struct stat DevStat; if (!fstat(RTFileToNative(hFile), &DevStat) && S_ISBLK(DevStat.st_mode)) { uint64_t cBlocks; uint32_t cbBlock; if (!ioctl(RTFileToNative(hFile), DKIOCGETBLOCKCOUNT, &cBlocks)) { if (!ioctl(RTFileToNative(hFile), DKIOCGETBLOCKSIZE, &cbBlock)) cbSize = cBlocks * cbBlock; else rc = RTErrConvertFromErrno(errno); } else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #elif defined(RT_OS_SOLARIS) struct stat DevStat; if ( !fstat(RTFileToNative(hFile), &DevStat) && ( S_ISBLK(DevStat.st_mode) || S_ISCHR(DevStat.st_mode))) { struct dk_minfo mediainfo; if (!ioctl(RTFileToNative(hFile), DKIOCGMEDIAINFO, &mediainfo)) cbSize = mediainfo.dki_capacity * mediainfo.dki_lbsize; else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #elif defined(RT_OS_FREEBSD) struct stat DevStat; if (!fstat(RTFileToNative(hFile), &DevStat) && S_ISCHR(DevStat.st_mode)) { off_t cbMedia = 0; if (!ioctl(RTFileToNative(hFile), DIOCGMEDIASIZE, &cbMedia)) { cbSize = cbMedia; } else rc = RTErrConvertFromErrno(errno); } else rc = VERR_INVALID_PARAMETER; #else /* Could be a block device */ rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, &cbSize); #endif if (RT_SUCCESS(rc) && (cbSize != 0)) *pcbSize = cbSize; else if (RT_SUCCESS(rc)) rc = VERR_NOT_SUPPORTED; } return rc; }
RTDECL(int) RTFileReadAllByHandleEx(RTFILE File, RTFOFF off, RTFOFF cbMax, uint32_t fFlags, void **ppvFile, size_t *pcbFile) { AssertReturn(!(fFlags & ~RTFILE_RDALL_VALID_MASK), VERR_INVALID_PARAMETER); /* * Save the current offset first. */ RTFOFF offOrg; int rc = RTFileSeek(File, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offOrg); if (RT_SUCCESS(rc)) { /* * Get the file size, adjust it and check that it might fit into memory. */ RTFOFF cbFile; rc = RTFileSeek(File, 0,RTFILE_SEEK_END, (uint64_t *)&cbFile); if (RT_SUCCESS(rc)) { RTFOFF cbAllocFile = cbFile > off ? cbFile - off : 0; if (cbAllocFile > cbMax) cbAllocFile = cbMax; size_t cbAllocMem = (size_t)cbAllocFile; if ((RTFOFF)cbAllocMem == cbAllocFile) { /* * Try allocate the required memory and initialize the header (hardcoded fun). */ void *pvHdr = RTMemAlloc(cbAllocMem + 32); if (pvHdr) { memset(pvHdr, 0xff, 32); *(size_t *)pvHdr = cbAllocMem; /* * Seek and read. */ rc = RTFileSeek(File, off, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) { void *pvFile = (uint8_t *)pvHdr + 32; rc = RTFileRead(File, pvFile, cbAllocMem, NULL); if (RT_SUCCESS(rc)) { /* * Success - fill in the return values. */ *ppvFile = pvFile; *pcbFile = cbAllocMem; } } if (RT_FAILURE(rc)) RTMemFree(pvHdr); } else rc = VERR_NO_MEMORY; } else rc = VERR_TOO_MUCH_DATA; } /* restore the position. */ RTFileSeek(File, offOrg, RTFILE_SEEK_BEGIN, NULL); } return rc; }
/** * Worker that removes a file. * * Currently used to delete both regular and special files. * * @returns IPRT status code, errors go via rtPathRmError. * @param pOpts The RM options. * @param pszPath The path to the file. * @param pObjInfo The FS object info for the file. */ static int rtPathRmOneFile(PRTPATHRMCMDOPTS pOpts, const char *pszPath, PRTFSOBJINFO pObjInfo) { int rc; if (pOpts->fVerbose) rtPathRmVerbose(pOpts, pszPath); /* * Wipe the file if requested and possible. */ if (pOpts->fSafeDelete && RTFS_IS_FILE(pObjInfo->Attr.fMode)) { /* Lazy init of the 0xff buffer. */ if (g_ab0xFF[0] != 0xff || g_ab0xFF[sizeof(g_ab0xFF) - 1] != 0xff) memset(g_ab0xFF, 0xff, sizeof(g_ab0xFF)); RTFILE hFile; rc = RTFileOpen(&hFile, pszPath, RTFILE_O_WRITE); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, "Opening '%s' for overwriting: %Rrc\n", pszPath, rc); for (unsigned iPass = 0; iPass < 3; iPass++) { uint8_t const *pabFiller = iPass == 1 ? g_abZeros : g_ab0xFF; size_t const cbFiller = iPass == 1 ? sizeof(g_abZeros) : sizeof(g_ab0xFF); rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error seeking to start of '%s': %Rrc\n", pszPath, rc); break; } for (RTFOFF cbLeft = pObjInfo->cbObject; cbLeft > 0; cbLeft -= cbFiller) { size_t cbToWrite = cbFiller; if (cbLeft < (RTFOFF)cbToWrite) cbToWrite = (size_t)cbLeft; rc = RTFileWrite(hFile, pabFiller, cbToWrite, NULL); if (RT_FAILURE(rc)) { rc = rtPathRmError(pOpts, pszPath, rc, "Error writing to '%s': %Rrc\n", pszPath, rc); break; } } } int rc2 = RTFileClose(hFile); if (RT_FAILURE(rc2) && RT_SUCCESS(rc)) return rtPathRmError(pOpts, pszPath, rc2, "Closing '%s' failed: %Rrc\n", pszPath, rc); if (RT_FAILURE(rc)) return rc; } /* * Remove the file. */ rc = RTFileDelete(pszPath); if (RT_FAILURE(rc)) return rtPathRmError(pOpts, pszPath, rc, RTFS_IS_FILE(pObjInfo->Attr.fMode) ? "Error removing regular file '%s': %Rrc\n" : "Error removing special file '%s': %Rrc\n", pszPath, rc); return rc; }
HRESULT Guest::taskCopyFileToGuest(GuestTask *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Do *not* take a write lock here since we don't (and won't) * touch any class-specific data (of IGuest) here - only the member functions * which get called here can do that. */ HRESULT rc = S_OK; try { ComObjPtr<Guest> pGuest = aTask->pGuest; /* Does our source file exist? */ if (!RTFileExists(aTask->strSource.c_str())) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Source file \"%s\" does not exist, or is not a file"), aTask->strSource.c_str()); } else { RTFILE fileSource; int vrc = RTFileOpen(&fileSource, aTask->strSource.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not open source file \"%s\" for reading (%Rrc)"), aTask->strSource.c_str(), vrc); } else { uint64_t cbSize; vrc = RTFileGetSize(fileSource, &cbSize); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not query file size of \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); } else { com::SafeArray<IN_BSTR> args; com::SafeArray<IN_BSTR> env; /* * Prepare tool command line. */ char szOutput[RTPATH_MAX]; if (RTStrPrintf(szOutput, sizeof(szOutput), "--output=%s", aTask->strDest.c_str()) <= sizeof(szOutput) - 1) { /* * Normalize path slashes, based on the detected guest. */ Utf8Str osType = mData.mOSTypeId; if ( osType.contains("Microsoft", Utf8Str::CaseInsensitive) || osType.contains("Windows", Utf8Str::CaseInsensitive)) { /* We have a Windows guest. */ RTPathChangeToDosSlashes(szOutput, true /* Force conversion. */); } else /* ... or something which isn't from Redmond ... */ { RTPathChangeToUnixSlashes(szOutput, true /* Force conversion. */); } args.push_back(Bstr(szOutput).raw()); /* We want to write a file ... */ } else { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error preparing command line")); } ComPtr<IProgress> execProgress; ULONG uPID; if (SUCCEEDED(rc)) { LogRel(("Copying file \"%s\" to guest \"%s\" (%u bytes) ...\n", aTask->strSource.c_str(), aTask->strDest.c_str(), cbSize)); /* * Okay, since we gathered all stuff we need until now to start the * actual copying, start the guest part now. */ rc = pGuest->executeAndWaitForTool(Bstr(VBOXSERVICE_TOOL_CAT).raw(), Bstr("Copying file to guest").raw(), ComSafeArrayAsInParam(args), ComSafeArrayAsInParam(env), Bstr(aTask->strUserName).raw(), Bstr(aTask->strPassword).raw(), ExecuteProcessFlag_WaitForProcessStartOnly, NULL, NULL, execProgress.asOutParam(), &uPID); if (FAILED(rc)) rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } if (SUCCEEDED(rc)) { BOOL fCompleted = FALSE; BOOL fCanceled = FALSE; uint64_t cbTransferedTotal = 0; SafeArray<BYTE> aInputData(_64K); while ( SUCCEEDED(execProgress->COMGETTER(Completed(&fCompleted))) && !fCompleted) { size_t cbToRead = cbSize; size_t cbRead = 0; if (cbSize) /* If we have nothing to read, take a shortcut. */ { /** @todo Not very efficient, but works for now. */ vrc = RTFileSeek(fileSource, cbTransferedTotal, RTFILE_SEEK_BEGIN, NULL /* poffActual */); if (RT_SUCCESS(vrc)) { vrc = RTFileRead(fileSource, (uint8_t*)aInputData.raw(), RT_MIN(cbToRead, _64K), &cbRead); /* * Some other error occured? There might be a chance that RTFileRead * could not resolve/map the native error code to an IPRT code, so just * print a generic error. */ if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not read from file \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); break; } } else { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Seeking file \"%s\" failed; offset = %RU64 (%Rrc)"), aTask->strSource.c_str(), cbTransferedTotal, vrc); break; } } /* Resize buffer to reflect amount we just have read. * Size 0 is allowed! */ aInputData.resize(cbRead); ULONG uFlags = ProcessInputFlag_None; /* Did we reach the end of the content we want to transfer (last chunk)? */ if ( (cbRead < _64K) /* Did we reach the last block which is exactly _64K? */ || (cbToRead - cbRead == 0) /* ... or does the user want to cancel? */ || ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) ) { uFlags |= ProcessInputFlag_EndOfFile; } ULONG uBytesWritten = 0; rc = pGuest->SetProcessInput(uPID, uFlags, 0 /* Infinite timeout */, ComSafeArrayAsInParam(aInputData), &uBytesWritten); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); break; } Assert(cbRead <= cbToRead); Assert(cbToRead >= cbRead); cbToRead -= cbRead; cbTransferedTotal += uBytesWritten; Assert(cbTransferedTotal <= cbSize); aTask->pProgress->SetCurrentOperationProgress(cbTransferedTotal / (cbSize / 100.0)); /* End of file reached? */ if (cbToRead == 0) break; /* Did the user cancel the operation above? */ if (fCanceled) break; /* Progress canceled by Main API? */ if ( SUCCEEDED(execProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Copy operation of file \"%s\" was canceled on guest side"), aTask->strSource.c_str()); break; } } if (SUCCEEDED(rc)) { /* * If we got here this means the started process either was completed, * canceled or we simply got all stuff transferred. */ ExecuteProcessStatus_T retStatus; ULONG uRetExitCode; rc = executeWaitForExit(uPID, execProgress, 0 /* No timeout */, &retStatus, &uRetExitCode); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } else { if ( uRetExitCode != 0 || retStatus != ExecuteProcessStatus_TerminatedNormally) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest process reported error %u (status: %u) while copying file \"%s\" to \"%s\""), uRetExitCode, retStatus, aTask->strSource.c_str(), aTask->strDest.c_str()); } } } if (SUCCEEDED(rc)) { if (fCanceled) { /* * In order to make the progress object to behave nicely, we also have to * notify the object with a complete event when it's canceled. */ aTask->pProgress->notifyComplete(VBOX_E_IPRT_ERROR, COM_IIDOF(IGuest), Guest::getStaticComponentName(), Guest::tr("Copying file \"%s\" canceled"), aTask->strSource.c_str()); } else { /* * Even if we succeeded until here make sure to check whether we really transfered * everything. */ if ( cbSize > 0 && cbTransferedTotal == 0) { /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write * to the destination -> access denied. */ rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Access denied when copying file \"%s\" to \"%s\""), aTask->strSource.c_str(), aTask->strDest.c_str()); } else if (cbTransferedTotal < cbSize) { /* If we did not copy all let the user know. */ rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Copying file \"%s\" failed (%u/%u bytes transfered)"), aTask->strSource.c_str(), cbTransferedTotal, cbSize); } else /* Yay, all went fine! */ aTask->pProgress->notifyComplete(S_OK); } } } } RTFileClose(fileSource); } } } catch (HRESULT aRC) { rc = aRC; } /* Clean up */ aTask->rc = rc; LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
void tstFileAppend1(RTTEST hTest) { /* * Open it write only and do some appending. * Checking that read fails and that the file position changes after the write. */ RTTestSub(hTest, "Basic 1"); RTFileDelete("tstFileAppend-1.tst"); RTFILE hFile = NIL_RTFILE; int rc = RTFileOpen(&hFile, "tstFileAppend-1.tst", RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_NONE | (0644 << RTFILE_O_CREATE_MODE_SHIFT) ); RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); uint64_t offActual = 42; uint64_t off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 0 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTESTI_CHECK_RC(RTFileWrite(hFile, "0123456789", 10, NULL), VINF_SUCCESS); offActual = 99; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 10 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu after first write\n", offActual); size_t cb = 4; char szBuf[256]; rc = RTFileRead(hFile, szBuf, 1, &cb); RTTESTI_CHECK_MSG(rc == VERR_ACCESS_DENIED || rc == VERR_INVALID_HANDLE, ("rc=%Rrc\n", rc)); offActual = 999; off = 5; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_BEGIN, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 5 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS); /* * Open it write only and do some more appending. * Checking the initial position and that it changes after the write. */ RTTestSub(hTest, "Basic 2"); rc = RTFileOpen(&hFile, "tstFileAppend-1.tst", RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_OPEN | RTFILE_O_DENY_NONE ); RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); offActual = 99; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 0 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu on 2nd open\n", offActual); RTTESTI_CHECK_RC(rc = RTFileWrite(hFile, "abcdefghij", 10, &cb), VINF_SUCCESS); offActual = 999; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 20 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu after 2nd write\n", offActual); RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS); /* * Open it read/write. * Check the initial position and read stuff. Then append some more and * check the new position and see that read returns 0/EOF. Finally, * do some seeking and read from a new position. */ RTTestSub(hTest, "Basic 3"); rc = RTFileOpen(&hFile, "tstFileAppend-1.tst", RTFILE_O_READWRITE | RTFILE_O_APPEND | RTFILE_O_OPEN | RTFILE_O_DENY_NONE ); RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); offActual = 9; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 0 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu on 3rd open\n", offActual); cb = 99; RTTESTI_CHECK_RC(rc = RTFileRead(hFile, szBuf, 10, &cb), VINF_SUCCESS); RTTESTI_CHECK(RT_FAILURE(rc) || cb == 10); RTTESTI_CHECK_MSG(RT_FAILURE(rc) || !memcmp(szBuf, "0123456789", 10), ("read the wrong stuff: %.10s - expected 0123456789\n", szBuf)); offActual = 999; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 10 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu on 1st open\n", offActual); RTTESTI_CHECK_RC(RTFileWrite(hFile, "klmnopqrst", 10, NULL), VINF_SUCCESS); offActual = 9999; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 30 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu after 3rd write\n", offActual); RTTESTI_CHECK_RC(rc = RTFileRead(hFile, szBuf, 1, NULL), VERR_EOF); cb = 99; RTTESTI_CHECK_RC(rc = RTFileRead(hFile, szBuf, 1, &cb), VINF_SUCCESS); RTTESTI_CHECK(cb == 0); offActual = 99999; off = 15; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_BEGIN, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 15 || RT_FAILURE(rc), ("offActual=%llu", offActual)); if (RT_SUCCESS(rc) && offActual == 15) { RTTESTI_CHECK_RC(rc = RTFileRead(hFile, szBuf, 10, NULL), VINF_SUCCESS); RTTESTI_CHECK_MSG(RT_FAILURE(rc) || !memcmp(szBuf, "fghijklmno", 10), ("read the wrong stuff: %.10s - expected fghijklmno\n", szBuf)); offActual = 9999999; off = 0; RTTESTI_CHECK_RC(rc = RTFileSeek(hFile, off, RTFILE_SEEK_CURRENT, &offActual), VINF_SUCCESS); RTTESTI_CHECK_MSG(offActual == 25 || RT_FAILURE(rc), ("offActual=%llu", offActual)); RTTestIPrintf(RTTESTLVL_INFO, "off=%llu after 2nd read\n", offActual); } RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS); /* * Open it read only + append and check that we cannot write to it. */ RTTestSub(hTest, "Basic 4"); rc = RTFileOpen(&hFile, "tstFileAppend-1.tst", RTFILE_O_READ | RTFILE_O_APPEND | RTFILE_O_OPEN | RTFILE_O_DENY_NONE); RTTESTI_CHECK_RC_RETV(rc, VINF_SUCCESS); rc = RTFileWrite(hFile, "pqrstuvwx", 10, &cb); RTTESTI_CHECK_MSG(rc == VERR_ACCESS_DENIED || rc == VERR_INVALID_HANDLE, ("rc=%Rrc\n", rc)); RTTESTI_CHECK_RC(RTFileClose(hFile), VINF_SUCCESS); RTTESTI_CHECK_RC(RTFileDelete("tstFileAppend-1.tst"), VINF_SUCCESS); }
RTDECL(int) RTFileCopyByHandlesEx(RTFILE FileSrc, RTFILE FileDst, PFNRTPROGRESS pfnProgress, void *pvUser) { /* * Validate input. */ AssertMsgReturn(RTFileIsValid(FileSrc), ("FileSrc=%RTfile\n", FileSrc), VERR_INVALID_PARAMETER); AssertMsgReturn(RTFileIsValid(FileDst), ("FileDst=%RTfile\n", FileDst), VERR_INVALID_PARAMETER); AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER); /* * Save file offset. */ RTFOFF offSrcSaved; int rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_CURRENT, (uint64_t *)&offSrcSaved); if (RT_FAILURE(rc)) return rc; /* * Get the file size. */ RTFOFF cbSrc; rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_END, (uint64_t *)&cbSrc); if (RT_FAILURE(rc)) return rc; /* * Allocate buffer. */ size_t cbBuf; uint8_t *pbBufFree = NULL; uint8_t *pbBuf; if (cbSrc < _512K) { cbBuf = 8*_1K; pbBuf = (uint8_t *)alloca(cbBuf); } else { cbBuf = _128K; pbBuf = pbBufFree = (uint8_t *)RTMemTmpAlloc(cbBuf); } if (pbBuf) { /* * Seek to the start of each file * and set the size of the destination file. */ rc = RTFileSeek(FileSrc, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) { rc = RTFileSeek(FileDst, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) rc = RTFileSetSize(FileDst, cbSrc); if (RT_SUCCESS(rc) && pfnProgress) rc = pfnProgress(0, pvUser); if (RT_SUCCESS(rc)) { /* * Copy loop. */ unsigned uPercentage = 0; RTFOFF off = 0; RTFOFF cbPercent = cbSrc / 100; RTFOFF offNextPercent = cbPercent; while (off < cbSrc) { /* copy block */ RTFOFF cbLeft = cbSrc - off; size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft; rc = RTFileRead(FileSrc, pbBuf, cbBlock, NULL); if (RT_FAILURE(rc)) break; rc = RTFileWrite(FileDst, pbBuf, cbBlock, NULL); if (RT_FAILURE(rc)) break; /* advance */ off += cbBlock; if (pfnProgress && offNextPercent < off) { while (offNextPercent < off) { uPercentage++; offNextPercent += cbPercent; } rc = pfnProgress(uPercentage, pvUser); if (RT_FAILURE(rc)) break; } } #if 0 /* * Copy OS specific data (EAs and stuff). */ rtFileCopyOSStuff(FileSrc, FileDst); #endif /* 100% */ if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc)) rc = pfnProgress(100, pvUser); } } RTMemTmpFree(pbBufFree); } else rc = VERR_NO_MEMORY; /* * Restore source position. */ RTFileSeek(FileSrc, offSrcSaved, RTFILE_SEEK_BEGIN, NULL); return rc; }
int SessionTaskUpdateAdditions::copyFileToGuest(GuestSession *pSession, PRTISOFSFILE pISO, Utf8Str const &strFileSource, const Utf8Str &strFileDest, bool fOptional, uint32_t *pcbSize) { AssertPtrReturn(pSession, VERR_INVALID_POINTER); AssertPtrReturn(pISO, VERR_INVALID_POINTER); /* pcbSize is optional. */ uint32_t cbOffset; size_t cbSize; int rc = RTIsoFsGetFileInfo(pISO, strFileSource.c_str(), &cbOffset, &cbSize); if (RT_FAILURE(rc)) { if (fOptional) return VINF_SUCCESS; return rc; } Assert(cbOffset); Assert(cbSize); rc = RTFileSeek(pISO->file, cbOffset, RTFILE_SEEK_BEGIN, NULL); /* Copy over the Guest Additions file to the guest. */ if (RT_SUCCESS(rc)) { LogRel(("Copying Guest Additions installer file \"%s\" to \"%s\" on guest ...\n", strFileSource.c_str(), strFileDest.c_str())); if (RT_SUCCESS(rc)) { SessionTaskCopyTo *pTask = new SessionTaskCopyTo(pSession /* GuestSession */, &pISO->file, cbOffset, cbSize, strFileDest, CopyFileFlag_None); AssertPtrReturn(pTask, VERR_NO_MEMORY); ComObjPtr<Progress> pProgressCopyTo; rc = pSession->startTaskAsync(Utf8StrFmt(GuestSession::tr("Copying Guest Additions installer file \"%s\" to \"%s\" on guest"), mSource.c_str(), strFileDest.c_str()), pTask, pProgressCopyTo); if (RT_SUCCESS(rc)) { BOOL fCanceled = FALSE; HRESULT hr = pProgressCopyTo->WaitForCompletion(-1); if ( SUCCEEDED(pProgressCopyTo->COMGETTER(Canceled)(&fCanceled)) && fCanceled) { rc = VERR_GENERAL_FAILURE; /* Fudge. */ } else if (FAILED(hr)) { Assert(FAILED(hr)); rc = VERR_GENERAL_FAILURE; /* Fudge. */ } } } } /** @todo Note: Since there is no file locking involved at the moment, there can be modifications * between finished copying, the verification and the actual execution. */ /* Determine where the installer image ended up and if it has the correct size. */ if (RT_SUCCESS(rc)) { LogRel(("Verifying Guest Additions installer file \"%s\" ...\n", strFileDest.c_str())); GuestFsObjData objData; int64_t cbSizeOnGuest; rc = pSession->fileQuerySizeInternal(strFileDest, &cbSizeOnGuest); #ifdef VBOX_SERVICE_ENVARG_BUG if (RT_FAILURE(rc)) { /* Ugly hack: Because older Guest Additions have problems with environment variable expansion in parameters we have to check an alternative location on Windows. So check for "%TEMP%\" being "C:\\Windows\\system32\\EMP" actually. */ if (strFileDest.startsWith("%TEMP%\\", RTCString::CaseSensitive)) { Utf8Str strFileDestBug = "C:\\Windows\\system32\\EMP" + strFileDest.substr(sizeof("%TEMP%\\") - sizeof(char)); rc = pSession->fileQuerySizeInternal(strFileDestBug, &cbSizeOnGuest); } } #endif if ( RT_SUCCESS(rc) && cbSize == (uint64_t)cbSizeOnGuest) { LogRel(("Guest Additions installer file \"%s\" successfully verified\n", strFileDest.c_str())); } else { if (RT_SUCCESS(rc)) /* Size does not match. */ rc = VERR_BROKEN_PIPE; /** @todo FInd a better error. */ } if (RT_SUCCESS(rc)) { if (pcbSize) *pcbSize = cbSizeOnGuest; } } return rc; }
int main() { int cErrors = 0; RTPrintf("tstFile: TESTING\n"); RTR3InitExeNoArguments(0); RTFILE File; int rc = RTFileOpen(&File, "tstFile#1.tst", RTFILE_O_READWRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_NONE); if (RT_FAILURE(rc)) { RTPrintf("tstFile: FATAL ERROR - Failed to open file #1. rc=%Rrc\n", rc); return 1; } RTFOFF cbMax = -2; rc = RTFileGetMaxSizeEx(File, &cbMax); if (RT_FAILURE(rc)) { RTPrintf("tstFile: RTFileGetMaxSizeEx failed: %Rrc\n", rc); cErrors++; } else if (cbMax <= 0) { RTPrintf("tstFile: RTFileGetMaxSizeEx failed: cbMax=%RTfoff\n", cbMax); cErrors++; } else if (RTFileGetMaxSize(File) != cbMax) { RTPrintf("tstFile: RTFileGetMaxSize failed; returns %RTfoff instead of %RTfoff\n", RTFileGetMaxSize(File), cbMax); cErrors++; } else RTPrintf("Maximum file size is %RTfoff bytes.\n", cbMax); /* grow file beyond 2G */ rc = RTFileSetSize(File, _2G + _1M); if (RT_FAILURE(rc)) { RTPrintf("Failed to grow file #1 to 2.001GB. rc=%Rrc\n", rc); cErrors++; } else { uint64_t cb; rc = RTFileGetSize(File, &cb); if (RT_FAILURE(rc)) { RTPrintf("Failed to get file size of #1. rc=%Rrc\n", rc); cErrors++; } else if (cb != _2G + _1M) { RTPrintf("RTFileGetSize return %RX64 bytes, expected %RX64.\n", cb, _2G + _1M); cErrors++; } else RTPrintf("tstFile: cb=%RX64\n", cb); /* * Try some writes at the beginning of the file. */ uint64_t offFile = RTFileTell(File); if (offFile != 0) { RTPrintf("RTFileTell -> %#RX64, expected 0 (#1)\n", offFile); cErrors++; } static const char szTestBuf[] = "Sausages and bacon for breakfast again!"; size_t cbWritten = 0; while (cbWritten < sizeof(szTestBuf)) { size_t cbWrittenPart; rc = RTFileWrite(File, &szTestBuf[cbWritten], sizeof(szTestBuf) - cbWritten, &cbWrittenPart); if (RT_FAILURE(rc)) break; cbWritten += cbWrittenPart; } if (RT_FAILURE(rc)) { RTPrintf("Failed to write to file #1 at offset 0. rc=%Rrc\n", rc); cErrors++; } else { /* check that it was written correctly. */ rc = RTFileSeek(File, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek offset 0 in file #1. rc=%Rrc\n", rc); cErrors++; } else { char szReadBuf[sizeof(szTestBuf)]; size_t cbRead = 0; while (cbRead < sizeof(szTestBuf)) { size_t cbReadPart; rc = RTFileRead(File, &szReadBuf[cbRead], sizeof(szTestBuf) - cbRead, &cbReadPart); if (RT_FAILURE(rc)) break; cbRead += cbReadPart; } if (RT_FAILURE(rc)) { RTPrintf("Failed to read from file #1 at offset 0. rc=%Rrc\n", rc); cErrors++; } else { if (!memcmp(szReadBuf, szTestBuf, sizeof(szTestBuf))) RTPrintf("tstFile: head write ok\n"); else { RTPrintf("Data read from file #1 at offset 0 differs from what we wrote there.\n"); cErrors++; } } } } /* * Try some writes at the end of the file. */ rc = RTFileSeek(File, _2G + _1M, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek to _2G + _1M in file #1. rc=%Rrc\n", rc); cErrors++; } else { offFile = RTFileTell(File); if (offFile != _2G + _1M) { RTPrintf("RTFileTell -> %#llx, expected %#llx (#2)\n", offFile, _2G + _1M); cErrors++; } else { cbWritten = 0; while (cbWritten < sizeof(szTestBuf)) { size_t cbWrittenPart; rc = RTFileWrite(File, &szTestBuf[cbWritten], sizeof(szTestBuf) - cbWritten, &cbWrittenPart); if (RT_FAILURE(rc)) break; cbWritten += cbWrittenPart; } if (RT_FAILURE(rc)) { RTPrintf("Failed to write to file #1 at offset 2G + 1M. rc=%Rrc\n", rc); cErrors++; } else { rc = RTFileSeek(File, offFile, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek offset %RX64 in file #1. rc=%Rrc\n", offFile, rc); cErrors++; } else { char szReadBuf[sizeof(szTestBuf)]; size_t cbRead = 0; while (cbRead < sizeof(szTestBuf)) { size_t cbReadPart; rc = RTFileRead(File, &szReadBuf[cbRead], sizeof(szTestBuf) - cbRead, &cbReadPart); if (RT_FAILURE(rc)) break; cbRead += cbReadPart; } if (RT_FAILURE(rc)) { RTPrintf("Failed to read from file #1 at offset 2G + 1M. rc=%Rrc\n", rc); cErrors++; } else { if (!memcmp(szReadBuf, szTestBuf, sizeof(szTestBuf))) RTPrintf("tstFile: tail write ok\n"); else { RTPrintf("Data read from file #1 at offset 2G + 1M differs from what we wrote there.\n"); cErrors++; } } } } } } /* * Some general seeking around. */ rc = RTFileSeek(File, _2G + 1, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek to _2G + 1 in file #1. rc=%Rrc\n", rc); cErrors++; } else { offFile = RTFileTell(File); if (offFile != _2G + 1) { RTPrintf("RTFileTell -> %#llx, expected %#llx (#3)\n", offFile, _2G + 1); cErrors++; } } /* seek end */ rc = RTFileSeek(File, 0, RTFILE_SEEK_END, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek to end of file #1. rc=%Rrc\n", rc); cErrors++; } else { offFile = RTFileTell(File); if (offFile != _2G + _1M + sizeof(szTestBuf)) /* assuming tail write was ok. */ { RTPrintf("RTFileTell -> %#RX64, expected %#RX64 (#4)\n", offFile, _2G + _1M + sizeof(szTestBuf)); cErrors++; } } /* seek start */ rc = RTFileSeek(File, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) { RTPrintf("Failed to seek to end of file #1. rc=%Rrc\n", rc); cErrors++; } else { offFile = RTFileTell(File); if (offFile != 0) { RTPrintf("RTFileTell -> %#llx, expected 0 (#5)\n", offFile); cErrors++; } } } /* * Cleanup. */ rc = RTFileClose(File); if (RT_FAILURE(rc)) { RTPrintf("Failed to close file #1. rc=%Rrc\n", rc); cErrors++; } rc = RTFileDelete("tstFile#1.tst"); if (RT_FAILURE(rc)) { RTPrintf("Failed to delete file #1. rc=%Rrc\n", rc); cErrors++; } /* * Summary */ if (cErrors == 0) RTPrintf("tstFile: SUCCESS\n"); else RTPrintf("tstFile: FAILURE - %d errors\n", cErrors); return !!cErrors; }
RTR3DECL(int) RTTarFileOpen(RTTAR hTar, PRTTARFILE phFile, const char *pszFilename, uint32_t fOpen) { /* Write only interface now. */ AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_PARAMETER); PRTTARINTERNAL pInt = hTar; RTTAR_VALID_RETURN(pInt); if (!pInt->hTarFile) return VERR_INVALID_HANDLE; if (fOpen & RTFILE_O_WRITE) { if (!(pInt->fOpenMode & RTFILE_O_WRITE)) return VERR_WRITE_PROTECT; if (pInt->fFileOpenForWrite) return VERR_TOO_MANY_OPEN_FILES; } int rc = VINF_SUCCESS; if (!(fOpen & RTFILE_O_WRITE)) { /* * Rewind the stream if necessary. */ if (!pInt->fFssAtStart) { if (pInt->hVfsFss != NIL_RTVFSFSSTREAM) { uint32_t cRefs = RTVfsFsStrmRelease(pInt->hVfsFss); Assert(cRefs != UINT32_MAX); pInt->hVfsFss = NIL_RTVFSFSSTREAM; } if (pInt->hVfsFile == NIL_RTVFSFILE) { rc = RTVfsFileFromRTFile(pInt->hTarFile, RTFILE_O_READ, true /*fLeaveOpen*/, &pInt->hVfsFile); if (RT_FAILURE(rc)) return rc; } RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(pInt->hVfsFile); rc = RTZipTarFsStreamFromIoStream(hVfsIos, 0 /*fFlags*/, &pInt->hVfsFss); RTVfsIoStrmRelease(hVfsIos); if (RT_FAILURE(rc)) return rc; } /* * Search the file system stream. */ pInt->fFssAtStart = false; for (;;) { char *pszName; RTVFSOBJTYPE enmType; RTVFSOBJ hVfsObj; rc = RTVfsFsStrmNext(pInt->hVfsFss, &pszName, &enmType, &hVfsObj); if (rc == VERR_EOF) return VERR_FILE_NOT_FOUND; if (RT_FAILURE(rc)) return rc; if (!RTStrCmp(pszName, pszFilename)) { if (enmType == RTVFSOBJTYPE_FILE || enmType == RTVFSOBJTYPE_IO_STREAM) rc = rtTarFileCreateHandleForReadOnly(pszName, RTVfsObjToIoStream(hVfsObj), fOpen, phFile); else { rc = VERR_UNEXPECTED_FS_OBJ_TYPE; RTStrFree(pszName); } RTVfsObjRelease(hVfsObj); break; } RTStrFree(pszName); RTVfsObjRelease(hVfsObj); } /* Search loop. */ } else { PRTTARFILEINTERNAL pFileInt = rtTarFileCreateForWrite(pInt, pszFilename, fOpen); if (!pFileInt) return VERR_NO_MEMORY; pInt->fFileOpenForWrite = true; /* If we are in write mode, we also in append mode. Add an dummy * header at the end of the current file. It will be filled by the * close operation. */ rc = RTFileSeek(pFileInt->pTar->hTarFile, 0, RTFILE_SEEK_END, &pFileInt->offStart); if (RT_SUCCESS(rc)) { RTTARRECORD record; RT_ZERO(record); rc = RTFileWrite(pFileInt->pTar->hTarFile, &record, sizeof(RTTARRECORD), NULL); } if (RT_SUCCESS(rc)) *phFile = (RTTARFILE)pFileInt; else { /* Cleanup on failure */ if (pFileInt->pszFilename) RTStrFree(pFileInt->pszFilename); RTMemFree(pFileInt); } } return rc; }
HRESULT Guest::taskUpdateGuestAdditions(GuestTask *aTask) { LogFlowFuncEnter(); AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); /* * Do *not* take a write lock here since we don't (and won't) * touch any class-specific data (of IGuest) here - only the member functions * which get called here can do that. */ HRESULT rc = S_OK; BOOL fCompleted; BOOL fCanceled; try { ComObjPtr<Guest> pGuest = aTask->pGuest; aTask->pProgress->SetCurrentOperationProgress(10); /* * Determine guest OS type and the required installer image. * At the moment only Windows guests are supported. */ Utf8Str installerImage; Bstr osTypeId; if ( SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam()))) && !osTypeId.isEmpty()) { Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */ if ( osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive) || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive)) { if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive)) installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE"; else installerImage = "VBOXWINDOWSADDITIONS_X86.EXE"; /* Since the installers are located in the root directory, * no further path processing needs to be done (yet). */ } else /* Everything else is not supported (yet). */ throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"), osTypeIdUtf8.c_str()); } else throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Could not detected guest OS type/version, please update manually")); Assert(!installerImage.isEmpty()); /* * Try to open the .ISO file and locate the specified installer. */ RTISOFSFILE iso; int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str()); if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->pProgress, Guest::tr("Invalid installation medium detected: \"%s\""), aTask->strSource.c_str()); } else { uint32_t cbOffset; size_t cbLength; vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength); if ( RT_SUCCESS(vrc) && cbOffset && cbLength) { vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(vrc)) rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"), aTask->strSource.c_str(), vrc); } else { switch (vrc) { case VERR_FILE_NOT_FOUND: rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Setup file was not found on installation medium \"%s\""), aTask->strSource.c_str()); break; default: rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""), vrc, aTask->strSource.c_str()); break; } } /* Specify the ouput path on the guest side. */ Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe"; if (RT_SUCCESS(vrc)) { /* Okay, we're ready to start our copy routine on the guest! */ aTask->pProgress->SetCurrentOperationProgress(15); /* Prepare command line args. */ com::SafeArray<IN_BSTR> args; com::SafeArray<IN_BSTR> env; args.push_back(Bstr("--output").raw()); /* We want to write a file ... */ args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */ if (SUCCEEDED(rc)) { ComPtr<IProgress> progressCat; ULONG uPID; /* * Start built-in "vbox_cat" tool (inside VBoxService) to * copy over/pipe the data into a file on the guest (with * system rights, no username/password specified). */ rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(), ExecuteProcessFlag_Hidden | ExecuteProcessFlag_WaitForProcessStartOnly, ComSafeArrayAsInParam(args), ComSafeArrayAsInParam(env), Bstr("").raw() /* Username. */, Bstr("").raw() /* Password */, 5 * 1000 /* Wait 5s for getting the process started. */, &uPID, progressCat.asOutParam(), &vrc); if (FAILED(rc)) { /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller * to silently fall back to "normal" (old) .ISO mounting. */ /* Due to a very limited COM error range we use vrc for a more detailed error * lookup to figure out what went wrong. */ switch (vrc) { /* Guest execution service is not (yet) ready. This basically means that either VBoxService * is not running (yet) or that the Guest Additions are too old (because VBoxService does not * support the guest execution feature in this version). */ case VERR_NOT_FOUND: LogRel(("Guest Additions seem not to be installed yet\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Guest Additions seem not to be installed or are not ready to update yet")); break; /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */ case VERR_INVALID_PARAMETER: LogRel(("Guest Additions are installed but don't supported automatic updating\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress, Guest::tr("Installed Guest Additions do not support automatic updating")); break; case VERR_TIMEOUT: LogRel(("Guest was unable to start copying the Guest Additions setup within time\n")); rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress, Guest::tr("Guest was unable to start copying the Guest Additions setup within time")); break; default: rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress, Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"), strInstallerPath.c_str(), vrc); break; } } else { LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str())); LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n", installerImage.c_str(), strInstallerPath.c_str())); aTask->pProgress->SetCurrentOperationProgress(20); /* Wait for process to exit ... */ SafeArray<BYTE> aInputData(_64K); while ( SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted))) && !fCompleted) { size_t cbRead; /* cbLength contains remaining bytes of our installer file * opened above to read. */ size_t cbToRead = RT_MIN(cbLength, _64K); if (cbToRead) { vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead); if ( cbRead && RT_SUCCESS(vrc)) { /* Resize buffer to reflect amount we just have read. */ if (cbRead > 0) aInputData.resize(cbRead); /* Did we reach the end of the content we want to transfer (last chunk)? */ ULONG uFlags = ProcessInputFlag_None; if ( (cbRead < _64K) /* Did we reach the last block which is exactly _64K? */ || (cbToRead - cbRead == 0) /* ... or does the user want to cancel? */ || ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) ) { uFlags |= ProcessInputFlag_EndOfFile; } /* Transfer the current chunk ... */ #ifdef DEBUG_andy LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength)); #endif ULONG uBytesWritten; rc = pGuest->SetProcessInput(uPID, uFlags, 10 * 1000 /* Wait 10s for getting the input data transfered. */, ComSafeArrayAsInParam(aInputData), &uBytesWritten); if (FAILED(rc)) { rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); break; } /* If task was canceled above also cancel the process execution. */ if (fCanceled) progressCat->Cancel(); #ifdef DEBUG_andy LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten)); #endif Assert(cbLength >= uBytesWritten); cbLength -= uBytesWritten; } else if (RT_FAILURE(vrc)) { rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"), installerImage.c_str(), cbToRead, cbLength, vrc); } } /* Internal progress canceled? */ if ( SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled))) && fCanceled) { aTask->pProgress->Cancel(); break; } } } } } RTIsoFsClose(&iso); if ( SUCCEEDED(rc) && ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && !fCanceled ) ) { /* * Installer was transferred successfully, so let's start it * (with system rights). */ LogRel(("Preparing to execute Guest Additions update ...\n")); aTask->pProgress->SetCurrentOperationProgress(66); /* Prepare command line args for installer. */ com::SafeArray<IN_BSTR> installerArgs; com::SafeArray<IN_BSTR> installerEnv; /** @todo Only Windows! */ installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */ /* Note that starting at Windows Vista the lovely session 0 separation applies: * This means that if we run an application with the profile/security context * of VBoxService (system rights!) we're not able to show any UI. */ installerArgs.push_back(Bstr("/S").raw()); /* We want to install in silent mode. */ installerArgs.push_back(Bstr("/l").raw()); /* ... and logging enabled. */ /* Don't quit VBoxService during upgrade because it still is used for this * piece of code we're in right now (that is, here!) ... */ installerArgs.push_back(Bstr("/no_vboxservice_exit").raw()); /* Tell the installer to report its current installation status * using a running VBoxTray instance via balloon messages in the * Windows taskbar. */ installerArgs.push_back(Bstr("/post_installstatus").raw()); /* * Start the just copied over installer with system rights * in silent mode on the guest. Don't use the hidden flag since there * may be pop ups the user has to process. */ ComPtr<IProgress> progressInstaller; ULONG uPID; rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(), ExecuteProcessFlag_WaitForProcessStartOnly, ComSafeArrayAsInParam(installerArgs), ComSafeArrayAsInParam(installerEnv), Bstr("").raw() /* Username */, Bstr("").raw() /* Password */, 10 * 1000 /* Wait 10s for getting the process started */, &uPID, progressInstaller.asOutParam(), &vrc); if (SUCCEEDED(rc)) { LogRel(("Guest Additions update is running ...\n")); /* If the caller does not want to wait for out guest update process to end, * complete the progress object now so that the caller can do other work. */ if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly) aTask->pProgress->notifyComplete(S_OK); else aTask->pProgress->SetCurrentOperationProgress(70); /* Wait until the Guest Additions installer finishes ... */ while ( SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted))) && !fCompleted) { if ( SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) { progressInstaller->Cancel(); break; } /* Progress canceled by Main API? */ if ( SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled))) && fCanceled) { break; } RTThreadSleep(100); } ExecuteProcessStatus_T retStatus; ULONG uRetExitCode, uRetFlags; rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus); if (SUCCEEDED(rc)) { if (fCompleted) { if (uRetExitCode == 0) { LogRel(("Guest Additions update successful!\n")); if ( SUCCEEDED(aTask->pProgress->COMGETTER(Completed(&fCompleted))) && !fCompleted) aTask->pProgress->notifyComplete(S_OK); } else { LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n", uRetExitCode, retStatus, uRetFlags)); rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"), uRetExitCode, retStatus, uRetFlags); } } else if ( SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled))) && fCanceled) { LogRel(("Guest Additions update was canceled\n")); rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress, Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"), uRetExitCode, retStatus, uRetFlags); } else { LogRel(("Guest Additions update was canceled by the user\n")); } } else rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } else rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest); } } } catch (HRESULT aRC) { rc = aRC; } /* Clean up */ aTask->rc = rc; LogFlowFunc(("rc=%Rhrc\n", rc)); LogFlowFuncLeave(); return VINF_SUCCESS; }
/** * Rewinds the tarball file handle and creates a gunzip | tar chain that * results in a filesystem stream. * * @returns VBox status code, failures with message. * @param hTarballFile The handle to the tarball file. * @param pszError Where to store an error message on failure. * @param cbError The size of the buffer @a pszError points to. * @param phTarFss Where to return the filesystem stream handle. * @param phFileManifest Where to return a manifest where the tarball is * gettting hashed. The entry will be called * "extpack" and be ready when the file system * stream is at an end. Optional. */ int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest) { Assert(cbError > 0); *pszError = '\0'; *phTarFss = NIL_RTVFSFSSTREAM; /* * Rewind the file and set up a VFS chain for it. */ int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc); RTVFSIOSTREAM hTarballIos; rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, &hTarballIos); if (RT_FAILURE(rc)) return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc); RTMANIFEST hFileManifest = NIL_RTMANIFEST; rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest); if (RT_SUCCESS(rc)) { RTVFSIOSTREAM hPtIos; rc = RTManifestEntryAddPassthruIoStream(hFileManifest, hTarballIos, "extpack", RTMANIFEST_ATTR_SHA256, true /*read*/, &hPtIos); if (RT_SUCCESS(rc)) { RTVFSIOSTREAM hGunzipIos; rc = RTZipGzipDecompressIoStream(hPtIos, 0 /*fFlags*/, &hGunzipIos); if (RT_SUCCESS(rc)) { RTVFSFSSTREAM hTarFss; rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss); if (RT_SUCCESS(rc)) { RTVfsIoStrmRelease(hPtIos); RTVfsIoStrmRelease(hGunzipIos); RTVfsIoStrmRelease(hTarballIos); *phTarFss = hTarFss; if (phFileManifest) *phFileManifest = hFileManifest; else RTManifestRelease(hFileManifest); return VINF_SUCCESS; } vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc); RTVfsIoStrmRelease(hGunzipIos); } else vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc); RTVfsIoStrmRelease(hPtIos); } else vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddPassthruIoStream failed: %Rrc", rc); RTManifestRelease(hFileManifest); } else vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); RTVfsIoStrmRelease(hTarballIos); return rc; }
static int vbglR3DnDHGProcessURIMessages(uint32_t uClientId, uint32_t *puScreenId, char *pszFormat, uint32_t cbFormat, uint32_t *pcbFormatRecv, void **ppvData, uint32_t cbData, size_t *pcbDataRecv) { /* Make a string list out of the uri data. */ RTCList<RTCString> uriList = RTCString(static_cast<char*>(*ppvData), *pcbDataRecv - 1).split("\r\n"); if (uriList.isEmpty()) return VINF_SUCCESS; uint32_t cbTmpData = _1M * 10; void *pvTmpData = RTMemAlloc(cbTmpData); if (!pvTmpData) return VERR_NO_MEMORY; /* Create and query the drop target directory. */ char pszDropDir[RTPATH_MAX]; int rc = vbglR3DnDCreateDropDir(pszDropDir, sizeof(pszDropDir)); if (RT_FAILURE(rc)) { RTMemFree(pvTmpData); return rc; } /* Patch the old drop data with the new drop directory, so the drop target * can find the files. */ RTCList<RTCString> guestUriList; for (size_t i = 0; i < uriList.size(); ++i) { const RTCString &strUri = uriList.at(i); /* Query the path component of a file URI. If this hasn't a * file scheme, null is returned. */ if (char *pszFilePath = RTUriFilePath(strUri.c_str(), URI_FILE_FORMAT_AUTO)) { RTCString strFullPath = RTCString().printf("%s%c%s", pszDropDir, RTPATH_SLASH, pszFilePath); char *pszNewUri = RTUriFileCreate(strFullPath.c_str()); if (pszNewUri) { guestUriList.append(pszNewUri); RTStrFree(pszNewUri); } } else guestUriList.append(strUri); } /* Cleanup the old data and write the new data back to the event. */ RTMemFree(*ppvData); RTCString newData = RTCString::join(guestUriList, "\r\n") + "\r\n"; *ppvData = RTStrDupN(newData.c_str(), newData.length()); *pcbDataRecv = newData.length() + 1; /* Lists for holding created files & directories in the case of a * rollback. */ RTCList<RTCString> guestDirList; RTCList<RTCString> guestFileList; char pszPathname[RTPATH_MAX]; uint32_t cbPathname = 0; bool fLoop = true; do { uint32_t uNextMsg; uint32_t cNextParms; rc = vbglR3DnDQueryNextHostMessageType(uClientId, &uNextMsg, &cNextParms, false); DO(("%Rrc - %d\n", rc , uNextMsg)); if (RT_SUCCESS(rc)) { switch(uNextMsg) { case DragAndDropSvc::HOST_DND_HG_SND_DIR: { uint32_t fMode = 0; rc = vbglR3DnDHGProcessSendDirMessage(uClientId, pszPathname, sizeof(pszPathname), &cbPathname, &fMode); if (RT_SUCCESS(rc)) { DO(("Got drop dir: %s - %o - %Rrc\n", pszPathname, fMode, rc)); char *pszNewDir = RTPathJoinA(pszDropDir, pszPathname); rc = RTDirCreate(pszNewDir, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRWXU, 0); if (!guestDirList.contains(pszNewDir)) guestDirList.append(pszNewDir); } break; } case DragAndDropSvc::HOST_DND_HG_SND_FILE: { uint32_t cbDataRecv; uint32_t fMode = 0; rc = vbglR3DnDHGProcessSendFileMessage(uClientId, pszPathname, sizeof(pszPathname), &cbPathname, pvTmpData, cbTmpData, &cbDataRecv, &fMode); if (RT_SUCCESS(rc)) { char *pszNewFile = RTPathJoinA(pszDropDir, pszPathname); DO(("Got drop file: %s - %d - %o - %Rrc\n", pszPathname, cbDataRecv, fMode, rc)); RTFILE hFile; rc = RTFileOpen(&hFile, pszNewFile, RTFILE_O_WRITE | RTFILE_O_APPEND | RTFILE_O_DENY_ALL | RTFILE_O_OPEN_CREATE); if (RT_SUCCESS(rc)) { rc = RTFileSeek(hFile, 0, RTFILE_SEEK_END, NULL); if (RT_SUCCESS(rc)) { rc = RTFileWrite(hFile, pvTmpData, cbDataRecv, 0); /* Valid UNIX mode? */ if ( RT_SUCCESS(rc) && (fMode & RTFS_UNIX_MASK)) rc = RTFileSetMode(hFile, (fMode & RTFS_UNIX_MASK) | RTFS_UNIX_IRUSR | RTFS_UNIX_IWUSR); } RTFileClose(hFile); if (!guestFileList.contains(pszNewFile)) guestFileList.append(pszNewFile); } } break; } case DragAndDropSvc::HOST_DND_HG_EVT_CANCEL: { rc = vbglR3DnDHGProcessCancelMessage(uClientId); if (RT_SUCCESS(rc)) rc = VERR_CANCELLED; /* Break out of the loop. */ } default: fLoop = false; break; } } else { if (rc == VERR_NO_DATA) rc = VINF_SUCCESS; break; } }while(fLoop); RTMemFree(pvTmpData); /* Cleanup on failure or if the user has canceled. */ if (RT_FAILURE(rc)) { /* Remove any stuff created. */ for (size_t i = 0; i < guestFileList.size(); ++i) RTFileDelete(guestFileList.at(i).c_str()); for (size_t i = 0; i < guestDirList.size(); ++i) RTDirRemove(guestDirList.at(i).c_str()); RTDirRemove(pszDropDir); } return rc; }
RTDECL(int) RTFileCompareByHandlesEx(RTFILE hFile1, RTFILE hFile2, uint32_t fFlags, PFNRTPROGRESS pfnProgress, void *pvUser) { /* * Validate input. */ AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE); AssertReturn(RTFileIsValid(hFile1), VERR_INVALID_HANDLE); AssertMsgReturn(!pfnProgress || VALID_PTR(pfnProgress), ("pfnProgress=%p\n", pfnProgress), VERR_INVALID_PARAMETER); AssertMsgReturn(!(fFlags & ~RTFILECOMP_FLAGS_MASK), ("%#x\n", fFlags), VERR_INVALID_PARAMETER); /* * Compare the file sizes first. */ uint64_t cbFile1; int rc = RTFileGetSize(hFile1, &cbFile1); if (RT_FAILURE(rc)) return rc; uint64_t cbFile2; rc = RTFileGetSize(hFile1, &cbFile2); if (RT_FAILURE(rc)) return rc; if (cbFile1 != cbFile2) return VERR_NOT_EQUAL; /* * Allocate buffer. */ size_t cbBuf; uint8_t *pbBuf1Free = NULL; uint8_t *pbBuf1; uint8_t *pbBuf2Free = NULL; uint8_t *pbBuf2; if (cbFile1 < _512K) { cbBuf = 8*_1K; pbBuf1 = (uint8_t *)alloca(cbBuf); pbBuf2 = (uint8_t *)alloca(cbBuf); } else { cbBuf = _128K; pbBuf1 = pbBuf1Free = (uint8_t *)RTMemTmpAlloc(cbBuf); pbBuf2 = pbBuf2Free = (uint8_t *)RTMemTmpAlloc(cbBuf); } if (pbBuf1 && pbBuf2) { /* * Seek to the start of each file * and set the size of the destination file. */ rc = RTFileSeek(hFile1, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc)) { rc = RTFileSeek(hFile2, 0, RTFILE_SEEK_BEGIN, NULL); if (RT_SUCCESS(rc) && pfnProgress) rc = pfnProgress(0, pvUser); if (RT_SUCCESS(rc)) { /* * Compare loop. */ unsigned uPercentage = 0; RTFOFF off = 0; RTFOFF cbPercent = cbFile1 / 100; RTFOFF offNextPercent = cbPercent; while (off < (RTFOFF)cbFile1) { /* read the blocks */ RTFOFF cbLeft = cbFile1 - off; size_t cbBlock = cbLeft >= (RTFOFF)cbBuf ? cbBuf : (size_t)cbLeft; rc = RTFileRead(hFile1, pbBuf1, cbBlock, NULL); if (RT_FAILURE(rc)) break; rc = RTFileRead(hFile2, pbBuf2, cbBlock, NULL); if (RT_FAILURE(rc)) break; /* compare */ if (memcmp(pbBuf1, pbBuf2, cbBlock)) { rc = VERR_NOT_EQUAL; break; } /* advance */ off += cbBlock; if (pfnProgress && offNextPercent < off) { while (offNextPercent < off) { uPercentage++; offNextPercent += cbPercent; } rc = pfnProgress(uPercentage, pvUser); if (RT_FAILURE(rc)) break; } } #if 0 /* * Compare OS specific data (EAs and stuff). */ if (RT_SUCCESS(rc)) rc = rtFileCompareOSStuff(hFile1, hFile2); #endif /* 100% */ if (pfnProgress && uPercentage < 100 && RT_SUCCESS(rc)) rc = pfnProgress(100, pvUser); } } } else rc = VERR_NO_MEMORY; RTMemTmpFree(pbBuf2Free); RTMemTmpFree(pbBuf1Free); return rc; }
int SessionTaskCopyTo::Run(void) { LogFlowThisFuncEnter(); ComObjPtr<GuestSession> pSession = mSession; Assert(!pSession.isNull()); AutoCaller autoCaller(pSession); if (FAILED(autoCaller.rc())) return autoCaller.rc(); if (mCopyFileFlags) { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Copy flags (%#x) not implemented yet"), mCopyFileFlags)); return VERR_INVALID_PARAMETER; } int rc; RTFILE fileLocal; PRTFILE pFile = &fileLocal; if (!mSourceFile) { /* Does our source file exist? */ if (!RTFileExists(mSource.c_str())) { rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Source file \"%s\" does not exist or is not a file"), mSource.c_str())); } else { rc = RTFileOpen(pFile, mSource.c_str(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) { rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Could not open source file \"%s\" for reading: %Rrc"), mSource.c_str(), rc)); } else { rc = RTFileGetSize(*pFile, &mSourceSize); if (RT_FAILURE(rc)) { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Could not query file size of \"%s\": %Rrc"), mSource.c_str(), rc)); } } } } else { pFile = mSourceFile; /* Size + offset are optional. */ } GuestProcessStartupInfo procInfo; procInfo.mName = Utf8StrFmt(GuestSession::tr("Copying file \"%s\" to the guest to \"%s\" (%RU64 bytes)"), mSource.c_str(), mDest.c_str(), mSourceSize); procInfo.mCommand = Utf8Str(VBOXSERVICE_TOOL_CAT); procInfo.mFlags = ProcessCreateFlag_Hidden; /* Set arguments.*/ procInfo.mArguments.push_back(Utf8StrFmt("--output=%s", mDest.c_str())); /** @todo Do we need path conversion? */ /* Startup process. */ ComObjPtr<GuestProcess> pProcess; rc = pSession->processCreateExInteral(procInfo, pProcess); if (RT_SUCCESS(rc)) rc = pProcess->startProcess(); if (RT_FAILURE(rc)) { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Unable to start guest process: %Rrc"), rc)); } else { GuestProcessWaitResult waitRes; BYTE byBuf[_64K]; BOOL fCanceled = FALSE; uint64_t cbWrittenTotal = 0; uint64_t cbToRead = mSourceSize; for (;;) { rc = pProcess->waitFor(ProcessWaitForFlag_StdIn, 30 * 1000 /* Timeout */, waitRes); if ( RT_FAILURE(rc) || ( waitRes.mResult != ProcessWaitResult_StdIn && waitRes.mResult != ProcessWaitResult_WaitFlagNotSupported)) { break; } /* If the guest does not support waiting for stdin, we now yield in * order to reduce the CPU load due to busy waiting. */ if (waitRes.mResult == ProcessWaitResult_WaitFlagNotSupported) RTThreadYield(); /* Optional, don't check rc. */ size_t cbRead = 0; if (mSourceSize) /* If we have nothing to write, take a shortcut. */ { /** @todo Not very efficient, but works for now. */ rc = RTFileSeek(*pFile, mSourceOffset + cbWrittenTotal, RTFILE_SEEK_BEGIN, NULL /* poffActual */); if (RT_SUCCESS(rc)) { rc = RTFileRead(*pFile, (uint8_t*)byBuf, RT_MIN(cbToRead, sizeof(byBuf)), &cbRead); /* * Some other error occured? There might be a chance that RTFileRead * could not resolve/map the native error code to an IPRT code, so just * print a generic error. */ if (RT_FAILURE(rc)) { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Could not read from file \"%s\" (%Rrc)"), mSource.c_str(), rc)); break; } } else { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Seeking file \"%s\" offset %RU64 failed: %Rrc"), mSource.c_str(), cbWrittenTotal, rc)); break; } } uint32_t fFlags = ProcessInputFlag_None; /* Did we reach the end of the content we want to transfer (last chunk)? */ if ( (cbRead < sizeof(byBuf)) /* Did we reach the last block which is exactly _64K? */ || (cbToRead - cbRead == 0) /* ... or does the user want to cancel? */ || ( SUCCEEDED(mProgress->COMGETTER(Canceled(&fCanceled))) && fCanceled) ) { fFlags |= ProcessInputFlag_EndOfFile; } uint32_t cbWritten; Assert(sizeof(byBuf) >= cbRead); rc = pProcess->writeData(0 /* StdIn */, fFlags, byBuf, cbRead, 30 * 1000 /* Timeout */, &cbWritten); if (RT_FAILURE(rc)) { setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Writing to file \"%s\" (offset %RU64) failed: %Rrc"), mDest.c_str(), cbWrittenTotal, rc)); break; } LogFlowThisFunc(("cbWritten=%RU32, cbToRead=%RU64, cbWrittenTotal=%RU64, cbFileSize=%RU64\n", cbWritten, cbToRead - cbWritten, cbWrittenTotal + cbWritten, mSourceSize)); /* Only subtract bytes reported written by the guest. */ Assert(cbToRead >= cbWritten); cbToRead -= cbWritten; /* Update total bytes written to the guest. */ cbWrittenTotal += cbWritten; Assert(cbWrittenTotal <= mSourceSize); /* Did the user cancel the operation above? */ if (fCanceled) break; /* Update the progress. * Watch out for division by zero. */ mSourceSize > 0 ? rc = setProgress((ULONG)(cbWrittenTotal * 100 / mSourceSize)) : rc = setProgress(100); if (RT_FAILURE(rc)) break; /* End of file reached? */ if (!cbToRead) break; } /* for */ if ( !fCanceled || RT_SUCCESS(rc)) { /* * Even if we succeeded until here make sure to check whether we really transfered * everything. */ if ( mSourceSize > 0 && cbWrittenTotal == 0) { /* If nothing was transfered but the file size was > 0 then "vbox_cat" wasn't able to write * to the destination -> access denied. */ rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Access denied when copying file \"%s\" to \"%s\""), mSource.c_str(), mDest.c_str())); } else if (cbWrittenTotal < mSourceSize) { /* If we did not copy all let the user know. */ rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed (%RU64/%RU64 bytes transfered)"), mSource.c_str(), cbWrittenTotal, mSourceSize)); } else { rc = pProcess->waitFor(ProcessWaitForFlag_Terminate, 30 * 1000 /* Timeout */, waitRes); if ( RT_FAILURE(rc) || waitRes.mResult != ProcessWaitResult_Terminate) { if (RT_FAILURE(rc)) rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed: %Rrc"), mSource.c_str(), rc)); else rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Waiting on termination for copying file \"%s\" failed with wait result %ld"), mSource.c_str(), waitRes.mResult)); } if (RT_SUCCESS(rc)) { ProcessStatus_T procStatus; LONG exitCode; if ( ( SUCCEEDED(pProcess->COMGETTER(Status(&procStatus))) && procStatus != ProcessStatus_TerminatedNormally) || ( SUCCEEDED(pProcess->COMGETTER(ExitCode(&exitCode))) && exitCode != 0) ) { rc = setProgressErrorMsg(VBOX_E_IPRT_ERROR, Utf8StrFmt(GuestSession::tr("Copying file \"%s\" failed with status %ld, exit code %ld"), mSource.c_str(), procStatus, exitCode)); /**@todo Add stringify methods! */ } } if (RT_SUCCESS(rc)) rc = setProgressSuccess(); } } if (!pProcess.isNull()) pProcess->uninit(); } /* processCreateExInteral */ if (!mSourceFile) /* Only close locally opened files. */ RTFileClose(*pFile); LogFlowFuncLeaveRC(rc); return rc; }
int main(int argc, char **argv) { RTR3InitExe(argc, &argv, 0); RTDIGESTTYPE enmDigestType = RTDIGESTTYPE_INVALID; const char *pszDigestType = "NotSpecified"; enum { kMethod_Full, kMethod_Block, kMethod_File, kMethod_CVAS } enmMethod = kMethod_Block; uint64_t offStart = 0; uint64_t cbMax = UINT64_MAX; bool fTestcase = false; static const RTGETOPTDEF s_aOptions[] = { { "--type", 't', RTGETOPT_REQ_STRING }, { "--method", 'm', RTGETOPT_REQ_STRING }, { "--help", 'h', RTGETOPT_REQ_NOTHING }, { "--length", 'l', RTGETOPT_REQ_UINT64 }, { "--offset", 'o', RTGETOPT_REQ_UINT64 }, { "--testcase", 'x', RTGETOPT_REQ_NOTHING }, }; int ch; RTGETOPTUNION ValueUnion; RTGETOPTSTATE GetState; RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); while ((ch = RTGetOpt(&GetState, &ValueUnion))) { switch (ch) { case 't': if (!RTStrICmp(ValueUnion.psz, "crc32")) { pszDigestType = "CRC32"; enmDigestType = RTDIGESTTYPE_CRC32; } else if (!RTStrICmp(ValueUnion.psz, "crc64")) { pszDigestType = "CRC64"; enmDigestType = RTDIGESTTYPE_CRC64; } else if (!RTStrICmp(ValueUnion.psz, "md2")) { pszDigestType = "MD2"; enmDigestType = RTDIGESTTYPE_MD2; } else if (!RTStrICmp(ValueUnion.psz, "md5")) { pszDigestType = "MD5"; enmDigestType = RTDIGESTTYPE_MD5; } else if (!RTStrICmp(ValueUnion.psz, "sha1")) { pszDigestType = "SHA-1"; enmDigestType = RTDIGESTTYPE_SHA1; } else if (!RTStrICmp(ValueUnion.psz, "sha224")) { pszDigestType = "SHA-224"; enmDigestType = RTDIGESTTYPE_SHA224; } else if (!RTStrICmp(ValueUnion.psz, "sha256")) { pszDigestType = "SHA-256"; enmDigestType = RTDIGESTTYPE_SHA256; } else if (!RTStrICmp(ValueUnion.psz, "sha384")) { pszDigestType = "SHA-384"; enmDigestType = RTDIGESTTYPE_SHA384; } else if (!RTStrICmp(ValueUnion.psz, "sha512")) { pszDigestType = "SHA-512"; enmDigestType = RTDIGESTTYPE_SHA512; } else if (!RTStrICmp(ValueUnion.psz, "sha512/224")) { pszDigestType = "SHA-512/224"; enmDigestType = RTDIGESTTYPE_SHA512T224; } else if (!RTStrICmp(ValueUnion.psz, "sha512/256")) { pszDigestType = "SHA-512/256"; enmDigestType = RTDIGESTTYPE_SHA512T256; } else { Error("Invalid digest type: %s\n", ValueUnion.psz); return 1; } break; case 'm': if (!RTStrICmp(ValueUnion.psz, "full")) enmMethod = kMethod_Full; else if (!RTStrICmp(ValueUnion.psz, "block")) enmMethod = kMethod_Block; else if (!RTStrICmp(ValueUnion.psz, "file")) enmMethod = kMethod_File; else if (!RTStrICmp(ValueUnion.psz, "cvas")) enmMethod = kMethod_CVAS; else { Error("Invalid digest method: %s\n", ValueUnion.psz); return 1; } break; case 'l': cbMax = ValueUnion.u64; break; case 'o': offStart = ValueUnion.u64; break; case 'x': fTestcase = true; break; case 'h': RTPrintf("usage: tstRTDigest -t <digest-type> [-o <offset>] [-l <length>] [-x] file [file2 [..]]\n"); return 1; case VINF_GETOPT_NOT_OPTION: { if (enmDigestType == RTDIGESTTYPE_INVALID) return Error("No digest type was specified\n"); switch (enmMethod) { case kMethod_Full: return Error("Full file method is not implemented\n"); case kMethod_File: if (offStart != 0 || cbMax != UINT64_MAX) return Error("The -l and -o options do not work with the 'file' method."); switch (enmDigestType) { case RTDIGESTTYPE_SHA1: { char *pszDigest; int rc = RTSha1DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) return Error("RTSha1Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc); RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); RTStrFree(pszDigest); break; } case RTDIGESTTYPE_SHA256: { char *pszDigest; int rc = RTSha256DigestFromFile(ValueUnion.psz, &pszDigest, NULL, NULL); if (RT_FAILURE(rc)) return Error("RTSha256Digest(%s,) -> %Rrc\n", ValueUnion.psz, rc); RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); RTStrFree(pszDigest); break; } default: return Error("The file method isn't implemented for this digest\n"); } break; case kMethod_Block: { RTFILE hFile; int rc = RTFileOpen(&hFile, ValueUnion.psz, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE); if (RT_FAILURE(rc)) return Error("RTFileOpen(,%s,) -> %Rrc\n", ValueUnion.psz, rc); if (offStart != 0) { rc = RTFileSeek(hFile, offStart, RTFILE_SEEK_BEGIN, NULL); if (RT_FAILURE(rc)) return Error("RTFileSeek(%s,%ull) -> %Rrc\n", ValueUnion.psz, offStart, rc); } uint64_t cbMaxLeft = cbMax; size_t cbRead; uint8_t abBuf[_64K]; char *pszDigest = (char *)&abBuf[0]; switch (enmDigestType) { case RTDIGESTTYPE_CRC32: { uint32_t uCRC32 = RTCrc32Start(); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; uCRC32 = RTCrc32Process(uCRC32, abBuf, cbRead); } uCRC32 = RTCrc32Finish(uCRC32); RTStrPrintf(pszDigest, sizeof(abBuf), "%08RX32", uCRC32); break; } case RTDIGESTTYPE_CRC64: { uint64_t uCRC64 = RTCrc64Start(); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; uCRC64 = RTCrc64Process(uCRC64, abBuf, cbRead); } uCRC64 = RTCrc64Finish(uCRC64); RTStrPrintf(pszDigest, sizeof(abBuf), "%016RX64", uCRC64); break; } case RTDIGESTTYPE_MD2: { RTMD2CONTEXT Ctx; RTMd2Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTMd2Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTMD2_HASH_SIZE]; RTMd2Final(&Ctx, abDigest); RTMd2ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_MD5: { RTMD5CONTEXT Ctx; RTMd5Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTMd5Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTMD5HASHSIZE]; RTMd5Final(abDigest, &Ctx); RTMd5ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA1: { RTSHA1CONTEXT Ctx; RTSha1Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha1Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA1_HASH_SIZE]; RTSha1Final(&Ctx, abDigest); RTSha1ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA256: { RTSHA256CONTEXT Ctx; RTSha256Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha256Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA256_HASH_SIZE]; RTSha256Final(&Ctx, abDigest); RTSha256ToString(abDigest, pszDigest, sizeof(abBuf)); break; } case RTDIGESTTYPE_SHA512: { RTSHA512CONTEXT Ctx; RTSha512Init(&Ctx); for (;;) { rc = MyReadFile(hFile, abBuf, sizeof(abBuf), &cbRead, &cbMaxLeft); if (RT_FAILURE(rc) || !cbRead) break; RTSha512Update(&Ctx, abBuf, cbRead); } uint8_t abDigest[RTSHA512_HASH_SIZE]; RTSha512Final(&Ctx, abDigest); RTSha512ToString(abDigest, pszDigest, sizeof(abBuf)); break; } default: return Error("Internal error #1\n"); } RTFileClose(hFile); if (RT_FAILURE(rc) && rc != VERR_EOF) { RTPrintf("Partial: %s %s\n", pszDigest, ValueUnion.psz); return Error("RTFileRead(%s) -> %Rrc\n", ValueUnion.psz, rc); } if (!fTestcase) RTPrintf("%s %s\n", pszDigest, ValueUnion.psz); else if (offStart) RTPrintf(" { &g_abRandom72KB[%#4llx], %5llu, \"%s\", \"%s %llu bytes @%llu\" },\n", offStart, cbMax - cbMaxLeft, pszDigest, pszDigestType, offStart, cbMax - cbMaxLeft); else RTPrintf(" { &g_abRandom72KB[0], %5llu, \"%s\", \"%s %llu bytes\" },\n", cbMax - cbMaxLeft, pszDigest, pszDigestType, cbMax - cbMaxLeft); break; } /* * Process a SHS response file: * http://csrc.nist.gov/groups/STM/cavp/index.html#03 */ case kMethod_CVAS: { RTCRDIGEST hDigest; int rc = RTCrDigestCreateByType(&hDigest, enmDigestType); if (RT_FAILURE(rc)) return Error("Failed to create digest calculator for %s: %Rrc", pszDigestType, rc); uint32_t const cbDigest = RTCrDigestGetHashSize(hDigest); if (!cbDigest || cbDigest >= _1K) return Error("Unexpected hash size: %#x\n", cbDigest); PRTSTREAM pFile; rc = RTStrmOpen(ValueUnion.psz, "r", &pFile); if (RT_FAILURE(rc)) return Error("Failed to open CVAS file '%s': %Rrc", ValueUnion.psz, rc); /* * Parse the input file. * ASSUME order: Len, Msg, MD. */ static char s_szLine[_256K]; char *psz; uint32_t cPassed = 0; uint32_t cErrors = 0; uint32_t iLine = 1; for (;;) { psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) break; /* Skip [L = 20] stuff. */ if (*psz == '[') continue; /* Message length. */ uint64_t cMessageBits; if (RTStrNICmp(psz, RT_STR_TUPLE("Len ="))) return Error("%s(%d): Expected 'Len =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 5); rc = RTStrToUInt64Full(psz, 0, &cMessageBits); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing length '%s': %Rrc\n", ValueUnion.psz, iLine, psz, rc); /* The message text. */ psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) return Error("%s(%d): Expected message text not EOF.", ValueUnion.psz, iLine); if (RTStrNICmp(psz, RT_STR_TUPLE("Msg ="))) return Error("%s(%d): Expected 'Msg =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 5); size_t const cbMessage = (cMessageBits + 7) / 8; static uint8_t s_abMessage[sizeof(s_szLine) / 2]; if (cbMessage > 0) { rc = RTStrConvertHexBytes(psz, s_abMessage, cbMessage, 0 /*fFlags*/); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing message '%.10s...': %Rrc\n", ValueUnion.psz, iLine, psz, rc); } /* The message digest. */ psz = MyGetNextSignificantLine(pFile, s_szLine, sizeof(s_szLine), &iLine, &rc); if (!psz) return Error("%s(%d): Expected message digest not EOF.", ValueUnion.psz, iLine); if (RTStrNICmp(psz, RT_STR_TUPLE("MD ="))) return Error("%s(%d): Expected 'MD =' found '%.10s...'", ValueUnion.psz, iLine, psz); psz = RTStrStripL(psz + 4); static uint8_t s_abExpectedDigest[_1K]; rc = RTStrConvertHexBytes(psz, s_abExpectedDigest, cbDigest, 0 /*fFlags*/); if (rc != VINF_SUCCESS) return Error("%s(%d): Error parsing message digest '%.10s...': %Rrc\n", ValueUnion.psz, iLine, psz, rc); /* * Do the testing. */ rc = RTCrDigestReset(hDigest); if (rc != VINF_SUCCESS) return Error("RTCrDigestReset failed: %Rrc", rc); rc = RTCrDigestUpdate(hDigest, s_abMessage, cbMessage); if (rc != VINF_SUCCESS) return Error("RTCrDigestUpdate failed: %Rrc", rc); static uint8_t s_abActualDigest[_1K]; rc = RTCrDigestFinal(hDigest, s_abActualDigest, cbDigest); if (rc != VINF_SUCCESS) return Error("RTCrDigestFinal failed: %Rrc", rc); if (memcmp(s_abActualDigest, s_abExpectedDigest, cbDigest) == 0) cPassed++; else { Error("%s(%d): Message digest mismatch. Expected %.*RThxs, got %.*RThxs.", ValueUnion.psz, iLine, cbDigest, s_abExpectedDigest, cbDigest, s_abActualDigest); cErrors++; } } RTStrmClose(pFile); if (cErrors > 0) return Error("Failed: %u error%s (%u passed)", cErrors, cErrors == 1 ? "" : "s", cPassed); RTPrintf("Passed %u test%s.\n", cPassed, cPassed == 1 ? "" : "s"); if (RT_FAILURE(rc)) return Error("Failed: %Rrc", rc); break; } default: return Error("Internal error #2\n"); } break; } default: return RTGetOptPrintError(ch, &ValueUnion); } } return 0; }