/** * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell} */ static DECLCALLBACK(int) rtManifestPtIos_Tell(void *pvThis, PRTFOFF poffActual) { PRTMANIFESTPTIOS pThis = (PRTMANIFESTPTIOS)pvThis; RTFOFF off = RTVfsIoStrmTell(pThis->hVfsIos); if (off < 0) return (int)off; *poffActual = off; return VINF_SUCCESS; }
RTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss) { /* * Input validation. */ AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE); *phVfsFss = NIL_RTVFSFSSTREAM; AssertPtrReturn(hVfsIosIn, VERR_INVALID_HANDLE); AssertReturn(!fFlags, VERR_INVALID_PARAMETER); RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn); AssertReturn(offStart >= 0, (int)offStart); uint32_t cRefs = RTVfsIoStrmRetain(hVfsIosIn); AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE); /* * Retain the input stream and create a new filesystem stream handle. */ PRTZIPTARFSSTREAM pThis; RTVFSFSSTREAM hVfsFss; int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFss, (void **)&pThis); if (RT_SUCCESS(rc)) { pThis->hVfsIos = hVfsIosIn; pThis->hVfsCurObj = NIL_RTVFSOBJ; pThis->pCurIosData = NULL; pThis->offStart = offStart; pThis->offNextHdr = offStart; pThis->fEndOfStream = false; pThis->rcFatal = VINF_SUCCESS; pThis->TarReader.enmPrevType= RTZIPTARTYPE_INVALID; pThis->TarReader.enmType = RTZIPTARTYPE_INVALID; pThis->TarReader.enmState = RTZIPTARREADERSTATE_FIRST; /* Don't check if it's a TAR stream here, do that in the rtZipTarFss_Next. */ *phVfsFss = hVfsFss; return VINF_SUCCESS; } RTVfsIoStrmRelease(hVfsIosIn); return rc; }
/** * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext} */ static DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj) { PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis; /* * Dispense with the current object. */ if (pThis->hVfsCurObj != NIL_RTVFSOBJ) { if (pThis->pCurIosData) { pThis->pCurIosData->fEndOfStream = true; pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile; pThis->pCurIosData = NULL; } RTVfsObjRelease(pThis->hVfsCurObj); pThis->hVfsCurObj = NIL_RTVFSOBJ; } /* * Check if we've already reached the end in some way. */ if (pThis->fEndOfStream) return VERR_EOF; if (pThis->rcFatal != VINF_SUCCESS) return pThis->rcFatal; /* * Make sure the input stream is in the right place. */ RTFOFF offHdr = RTVfsIoStrmTell(pThis->hVfsIos); while ( offHdr >= 0 && offHdr < pThis->offNextHdr) { int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - offHdr); if (RT_FAILURE(rc)) { /** @todo Ignore if we're at the end of the stream? */ return pThis->rcFatal = rc; } offHdr = RTVfsIoStrmTell(pThis->hVfsIos); } if (offHdr < 0) return pThis->rcFatal = (int)offHdr; if (offHdr > pThis->offNextHdr) return pThis->rcFatal = VERR_INTERNAL_ERROR_3; /* * Consume TAR headers. */ size_t cbHdrs = 0; int rc; do { /* * Read the next header. */ RTZIPTARHDR Hdr; size_t cbRead; rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; if (rc == VINF_EOF && cbRead == 0) { pThis->fEndOfStream = true; return rtZipTarReaderIsAtEnd(&pThis->TarReader) ? VERR_EOF : VERR_TAR_UNEXPECTED_EOS; } if (cbRead != sizeof(Hdr)) return pThis->rcFatal = VERR_TAR_UNEXPECTED_EOS; cbHdrs += sizeof(Hdr); /* * Parse the it. */ rc = rtZipTarReaderParseHeader(&pThis->TarReader, &Hdr); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; } while (rtZipTarReaderExpectingMoreHeaders(&pThis->TarReader)); pThis->offNextHdr = offHdr + cbHdrs; /* * Fill an object info structure from the current TAR state. */ RTFSOBJINFO Info; rc = rtZipTarReaderGetFsObjInfo(&pThis->TarReader, &Info); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; /* * Create an object of the appropriate type. */ RTVFSOBJTYPE enmType; RTVFSOBJ hVfsObj; RTFMODE fType = Info.Attr.fMode & RTFS_TYPE_MASK; if (rtZipTarReaderIsHardlink(&pThis->TarReader)) fType = RTFS_TYPE_SYMLINK; switch (fType) { /* * Files are represented by a VFS I/O stream. */ case RTFS_TYPE_FILE: { RTVFSIOSTREAM hVfsIos; PRTZIPTARIOSTREAM pIosData; rc = RTVfsNewIoStream(&g_rtZipTarFssIosOps, sizeof(*pIosData), RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN, NIL_RTVFS, NIL_RTVFSLOCK, &hVfsIos, (void **)&pIosData); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; pIosData->BaseObj.offHdr = offHdr; pIosData->BaseObj.pTarReader= &pThis->TarReader; pIosData->BaseObj.ObjInfo = Info; pIosData->cbFile = Info.cbObject; pIosData->offFile = 0; pIosData->cbPadding = (uint32_t)(Info.cbAllocated - Info.cbObject); pIosData->fEndOfStream = false; pIosData->hVfsIos = pThis->hVfsIos; RTVfsIoStrmRetain(pThis->hVfsIos); pThis->pCurIosData = pIosData; pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding; enmType = RTVFSOBJTYPE_IO_STREAM; hVfsObj = RTVfsObjFromIoStream(hVfsIos); RTVfsIoStrmRelease(hVfsIos); break; } /* * We represent hard links using a symbolic link object. This fits * best with the way TAR stores it and there is currently no better * fitting VFS type alternative. */ case RTFS_TYPE_SYMLINK: { RTVFSSYMLINK hVfsSym; PRTZIPTARBASEOBJ pBaseObjData; rc = RTVfsNewSymlink(&g_rtZipTarFssSymOps, sizeof(*pBaseObjData), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsSym, (void **)&pBaseObjData); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; pBaseObjData->offHdr = offHdr; pBaseObjData->pTarReader= &pThis->TarReader; pBaseObjData->ObjInfo = Info; enmType = RTVFSOBJTYPE_SYMLINK; hVfsObj = RTVfsObjFromSymlink(hVfsSym); RTVfsSymlinkRelease(hVfsSym); break; } /* * All other objects are repesented using a VFS base object since they * carry no data streams (unless some TAR extension implements extended * attributes / alternative streams). */ case RTFS_TYPE_DEV_BLOCK: case RTFS_TYPE_DEV_CHAR: case RTFS_TYPE_DIRECTORY: case RTFS_TYPE_FIFO: { PRTZIPTARBASEOBJ pBaseObjData; rc = RTVfsNewBaseObj(&g_rtZipTarFssBaseObjOps, sizeof(*pBaseObjData), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsObj, (void **)&pBaseObjData); if (RT_FAILURE(rc)) return pThis->rcFatal = rc; pBaseObjData->offHdr = offHdr; pBaseObjData->pTarReader= &pThis->TarReader; pBaseObjData->ObjInfo = Info; enmType = RTVFSOBJTYPE_BASE; break; } default: AssertFailed(); return pThis->rcFatal = VERR_INTERNAL_ERROR_5; } pThis->hVfsCurObj = hVfsObj; /* * Set the return data and we're done. */ if (ppszName) { rc = RTStrDupEx(ppszName, pThis->TarReader.szName); if (RT_FAILURE(rc)) return rc; } if (phVfsObj) { RTVfsObjRetain(hVfsObj); *phVfsObj = hVfsObj; } if (penmType) *penmType = enmType; return VINF_SUCCESS; }