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; }
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; }
static int ebml_StartSubElement(EbmlGlobal *glob, uint64_t *ebmlLoc, uint32_t class_id) { // todo this is always taking 8 bytes, this may need later optimization // this is a key that says lenght unknown uint64_t unknownLen = UINT64_C(0x01FFFFFFFFFFFFFF); ebml_WriteID(glob, class_id); *ebmlLoc = RTFileTell(glob->file); return ebml_WriteU64(glob, RT_H2BE_U64(unknownLen)); }
/** @copydoc KRDROPS::pfnTell */ static KFOFF krdrRTFileTell(PKRDR pRdr) { PKRDRFILE pRdrFile = (PKRDRFILE)pRdr; /* * If the offset is undefined, try figure out what it is. */ if (pRdrFile->off == -1) { pRdrFile->off = RTFileTell(pRdrFile->File); if (pRdrFile->off < 0) pRdrFile->off = -1; } return pRdrFile->off; }
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; }
/** * Worker function for dbgfR3CoreWrite() which does the writing. * * @returns VBox status code * @param pVM Pointer to the VM. * @param hFile The file to write to. Caller closes this. */ static int dbgfR3CoreWriteWorker(PVM pVM, RTFILE hFile) { /* * Collect core information. */ uint32_t const cu32MemRanges = dbgfR3GetRamRangeCount(pVM); uint16_t const cMemRanges = cu32MemRanges < UINT16_MAX - 1 ? cu32MemRanges : UINT16_MAX - 1; /* One PT_NOTE Program header */ uint16_t const cProgHdrs = cMemRanges + 1; DBGFCOREDESCRIPTOR CoreDescriptor; RT_ZERO(CoreDescriptor); CoreDescriptor.u32Magic = DBGFCORE_MAGIC; CoreDescriptor.u32FmtVersion = DBGFCORE_FMT_VERSION; CoreDescriptor.cbSelf = sizeof(CoreDescriptor); CoreDescriptor.u32VBoxVersion = VBOX_FULL_VERSION; CoreDescriptor.u32VBoxRevision = VMMGetSvnRev(); CoreDescriptor.cCpus = pVM->cCpus; Log((DBGFLOG_NAME ": CoreDescriptor Version=%u Revision=%u\n", CoreDescriptor.u32VBoxVersion, CoreDescriptor.u32VBoxRevision)); /* * Compute the file layout (see pg_dbgf_vmcore). */ uint64_t const offElfHdr = RTFileTell(hFile); uint64_t const offNoteSection = offElfHdr + sizeof(Elf64_Ehdr); uint64_t const offLoadSections = offNoteSection + sizeof(Elf64_Phdr); uint64_t const cbLoadSections = cMemRanges * sizeof(Elf64_Phdr); uint64_t const offCoreDescriptor = offLoadSections + cbLoadSections; uint64_t const cbCoreDescriptor = Elf64NoteSectionSize(g_pcszCoreVBoxCore, sizeof(CoreDescriptor)); uint64_t const offCpuDumps = offCoreDescriptor + cbCoreDescriptor; uint64_t const cbCpuDumps = pVM->cCpus * Elf64NoteSectionSize(g_pcszCoreVBoxCpu, sizeof(DBGFCORECPU)); uint64_t const offMemory = offCpuDumps + cbCpuDumps; uint64_t const offNoteSectionData = offCoreDescriptor; uint64_t const cbNoteSectionData = cbCoreDescriptor + cbCpuDumps; /* * Write ELF header. */ int rc = Elf64WriteElfHdr(hFile, cProgHdrs, 0 /* cSecHdrs */); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": Elf64WriteElfHdr failed. rc=%Rrc\n", rc)); return rc; } /* * Write PT_NOTE program header. */ Assert(RTFileTell(hFile) == offNoteSection); rc = Elf64WriteProgHdr(hFile, PT_NOTE, PF_R, offNoteSectionData, /* file offset to contents */ cbNoteSectionData, /* size in core file */ cbNoteSectionData, /* size in memory */ 0); /* physical address */ if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": Elf64WritreProgHdr failed for PT_NOTE. rc=%Rrc\n", rc)); return rc; } /* * Write PT_LOAD program header for each memory range. */ Assert(RTFileTell(hFile) == offLoadSections); uint64_t offMemRange = offMemory; for (uint16_t iRange = 0; iRange < cMemRanges; iRange++) { RTGCPHYS GCPhysStart; RTGCPHYS GCPhysEnd; bool fIsMmio; rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, &fIsMmio); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange failed for iRange(%u) rc=%Rrc\n", iRange, rc)); return rc; } uint64_t cbMemRange = GCPhysEnd - GCPhysStart + 1; uint64_t cbFileRange = fIsMmio ? 0 : cbMemRange; Log((DBGFLOG_NAME ": PGMR3PhysGetRange iRange=%u GCPhysStart=%#x GCPhysEnd=%#x cbMemRange=%u\n", iRange, GCPhysStart, GCPhysEnd, cbMemRange)); rc = Elf64WriteProgHdr(hFile, PT_LOAD, PF_R, offMemRange, /* file offset to contents */ cbFileRange, /* size in core file */ cbMemRange, /* size in memory */ GCPhysStart); /* physical address */ if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": Elf64WriteProgHdr failed for memory range(%u) cbFileRange=%u cbMemRange=%u rc=%Rrc\n", iRange, cbFileRange, cbMemRange, rc)); return rc; } offMemRange += cbFileRange; } /* * Write the Core descriptor note header and data. */ Assert(RTFileTell(hFile) == offCoreDescriptor); rc = Elf64WriteNoteHdr(hFile, NT_VBOXCORE, g_pcszCoreVBoxCore, &CoreDescriptor, sizeof(CoreDescriptor)); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr failed for Note '%s' rc=%Rrc\n", g_pcszCoreVBoxCore, rc)); return rc; } /* * Write the CPU context note headers and data. */ Assert(RTFileTell(hFile) == offCpuDumps); PDBGFCORECPU pDbgfCoreCpu = (PDBGFCORECPU)RTMemAlloc(sizeof(*pDbgfCoreCpu)); if (RT_UNLIKELY(!pDbgfCoreCpu)) { LogRel((DBGFLOG_NAME ": failed to alloc %u bytes for DBGFCORECPU\n", sizeof(*pDbgfCoreCpu))); return VERR_NO_MEMORY; } for (uint32_t iCpu = 0; iCpu < pVM->cCpus; iCpu++) { PVMCPU pVCpu = &pVM->aCpus[iCpu]; PCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu); if (RT_UNLIKELY(!pCtx)) { LogRel((DBGFLOG_NAME ": CPUMQueryGuestCtxPtr failed for vCPU[%u]\n", iCpu)); RTMemFree(pDbgfCoreCpu); return VERR_INVALID_POINTER; } RT_BZERO(pDbgfCoreCpu, sizeof(*pDbgfCoreCpu)); dbgfR3GetCoreCpu(pCtx, pDbgfCoreCpu); rc = Elf64WriteNoteHdr(hFile, NT_VBOXCPU, g_pcszCoreVBoxCpu, pDbgfCoreCpu, sizeof(*pDbgfCoreCpu)); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": Elf64WriteNoteHdr failed for vCPU[%u] rc=%Rrc\n", iCpu, rc)); RTMemFree(pDbgfCoreCpu); return rc; } } RTMemFree(pDbgfCoreCpu); pDbgfCoreCpu = NULL; /* * Write memory ranges. */ Assert(RTFileTell(hFile) == offMemory); for (uint16_t iRange = 0; iRange < cMemRanges; iRange++) { RTGCPHYS GCPhysStart; RTGCPHYS GCPhysEnd; bool fIsMmio; rc = PGMR3PhysGetRange(pVM, iRange, &GCPhysStart, &GCPhysEnd, NULL /* pszDesc */, &fIsMmio); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": PGMR3PhysGetRange(2) failed for iRange(%u) rc=%Rrc\n", iRange, rc)); return rc; } if (fIsMmio) continue; /* * Write page-by-page of this memory range. * * The read function may fail on MMIO ranges, we write these as zero * pages for now (would be nice to have the VGA bits there though). */ uint64_t cbMemRange = GCPhysEnd - GCPhysStart + 1; uint64_t cPages = cbMemRange >> PAGE_SHIFT; for (uint64_t iPage = 0; iPage < cPages; iPage++) { uint8_t abPage[PAGE_SIZE]; rc = PGMPhysSimpleReadGCPhys(pVM, abPage, GCPhysStart + (iPage << PAGE_SHIFT), sizeof(abPage)); if (RT_FAILURE(rc)) { if (rc != VERR_PGM_PHYS_PAGE_RESERVED) LogRel((DBGFLOG_NAME ": PGMPhysRead failed for iRange=%u iPage=%u. rc=%Rrc. Ignoring...\n", iRange, iPage, rc)); RT_ZERO(abPage); } rc = RTFileWrite(hFile, abPage, sizeof(abPage), NULL /* all */); if (RT_FAILURE(rc)) { LogRel((DBGFLOG_NAME ": RTFileWrite failed. iRange=%u iPage=%u rc=%Rrc\n", iRange, iPage, rc)); return rc; } } } return rc; }
int Ebml_WriteWebMBlock(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const vpx_codec_cx_pkt_t *pkt) { uint16_t block_timecode = 0; int64_t pts_ms; int start_cluster = 0; int rc = VINF_SUCCESS; /* Calculate the PTS of this frame in milliseconds */ pts_ms = pkt->data.frame.pts * 1000 * (uint64_t)cfg->g_timebase.num / (uint64_t)cfg->g_timebase.den; if (pts_ms <= glob->last_pts_ms) pts_ms = glob->last_pts_ms + 1; glob->last_pts_ms = pts_ms; /* Calculate the relative time of this block */ if (pts_ms - glob->cluster_timecode > 65536) start_cluster = 1; else block_timecode = (uint16_t)(pts_ms - glob->cluster_timecode); int fKeyframe = (pkt->data.frame.flags & VPX_FRAME_IS_KEY); if (start_cluster || fKeyframe) { if (glob->cluster_open) rc = ebml_EndSubElement(glob, glob->startCluster); /* Open the new cluster */ block_timecode = 0; glob->cluster_open = 1; glob->cluster_timecode = (uint32_t)pts_ms; glob->cluster_pos = RTFileTell(glob->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &glob->startCluster, Cluster); //cluster if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, Timecode, glob->cluster_timecode); /* Save a cue point if this is a keyframe. */ if (fKeyframe) { struct cue_entry *cue; glob->cue_list = (cue_entry*)RTMemRealloc(glob->cue_list, (glob->cues+1) * sizeof(cue_entry)); cue = &glob->cue_list[glob->cues]; cue->time = glob->cluster_timecode; cue->loc = glob->cluster_pos; glob->cues++; } } /* Write the Simple Block */ if (RT_SUCCESS(rc)) rc = ebml_WriteID(glob, SimpleBlock); uint32_t block_length = pkt->data.frame.sz + 4; block_length |= 0x10000000; if (RT_SUCCESS(rc)) rc = ebml_WriteU32(glob, RT_H2BE_U32(block_length)); uint8_t track_number = 0x80 | 1; if (RT_SUCCESS(rc)) rc = ebml_WriteU8(glob, track_number); if (RT_SUCCESS(rc)) rc = ebml_WriteU16(glob, RT_H2BE_U16(block_timecode)); uint8_t flags = 0; if (fKeyframe) flags |= 0x80; if (pkt->data.frame.flags & VPX_FRAME_IS_INVISIBLE) flags |= 0x08; if (RT_SUCCESS(rc)) rc = ebml_WriteU8(glob, flags); if (RT_SUCCESS(rc)) rc = ebml_Write(glob, pkt->data.frame.buf, pkt->data.frame.sz); return rc; }
int Ebml_WriteWebMFileHeader(EbmlGlobal *glob, const vpx_codec_enc_cfg_t *cfg, const struct vpx_rational *fps) { int rc = VINF_SUCCESS; { uint64_t start; rc = ebml_StartSubElement(glob, &start, EBML); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLVersion, 1); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLReadVersion, 1); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLMaxIDLength, 4); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, EBMLMaxSizeLength, 8); if (RT_SUCCESS(rc)) rc = Ebml_SerializeString(glob, DocType, "webm"); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, DocTypeVersion, 2); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, DocTypeReadVersion, 2); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, start); } { if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &glob->startSegment, Segment); glob->position_reference = RTFileTell(glob->file); glob->framerate = *fps; if (RT_SUCCESS(rc)) rc = Ebml_WriteWebMSeekInfo(glob); { uint64_t trackStart; glob->track_pos = RTFileTell(glob->file); if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &trackStart, Tracks); { uint32_t trackNumber = 1; uint32_t trackID = 0; uint64_t start; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &start, TrackEntry); if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, TrackNumber, trackNumber); glob->track_id_pos = RTFileTell(glob->file); ebml_SerializeUnsigned32(glob, TrackUID, trackID); Ebml_SerializeUnsigned(glob, TrackType, 1); //video is always 1 Ebml_SerializeString(glob, CodecID, "V_VP8"); { uint64_t videoStart; if (RT_SUCCESS(rc)) rc = ebml_StartSubElement(glob, &videoStart, Video); uint32_t pixelWidth = cfg->g_w; if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, PixelWidth, pixelWidth); uint32_t pixelHeight = cfg->g_h; if (RT_SUCCESS(rc)) rc = Ebml_SerializeUnsigned(glob, PixelHeight, pixelHeight); double frameRate = (double)fps->num / (double)fps->den; if (RT_SUCCESS(rc)) rc = Ebml_SerializeFloat(glob, FrameRate, frameRate); if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, videoStart); } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, start); //Track Entry } if (RT_SUCCESS(rc)) rc = ebml_EndSubElement(glob, trackStart); } // segment element is open } 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; }