tarvfs.cpp revision 0bb0c0c0e3f9e5fdb3e745715dde1af951c04998
43af8389304c77c3d4db525de8907cb74207c380vboxsync * IPRT - TAR Virtual Filesystem.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Copyright (C) 2010 Oracle Corporation
43af8389304c77c3d4db525de8907cb74207c380vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
43af8389304c77c3d4db525de8907cb74207c380vboxsync * available from http://www.virtualbox.org. This file is free software;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * you can redistribute it and/or modify it under the terms of the GNU
43af8389304c77c3d4db525de8907cb74207c380vboxsync * General Public License (GPL) as published by the Free Software
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
43af8389304c77c3d4db525de8907cb74207c380vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
43af8389304c77c3d4db525de8907cb74207c380vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * The contents of this file may alternatively be used under the terms
43af8389304c77c3d4db525de8907cb74207c380vboxsync * of the Common Development and Distribution License Version 1.0
43af8389304c77c3d4db525de8907cb74207c380vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
43af8389304c77c3d4db525de8907cb74207c380vboxsync * VirtualBox OSE distribution, in which case the provisions of the
43af8389304c77c3d4db525de8907cb74207c380vboxsync * CDDL are applicable instead of those of the GPL.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * You may elect to license modified versions of this file under the
43af8389304c77c3d4db525de8907cb74207c380vboxsync * terms and conditions of either the GPL or the CDDL or both.
43af8389304c77c3d4db525de8907cb74207c380vboxsync/******************************************************************************
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Header Files *
43af8389304c77c3d4db525de8907cb74207c380vboxsync ******************************************************************************/
43af8389304c77c3d4db525de8907cb74207c380vboxsync/*******************************************************************************
43af8389304c77c3d4db525de8907cb74207c380vboxsync* Structures and Typedefs *
43af8389304c77c3d4db525de8907cb74207c380vboxsync*******************************************************************************/
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Tar directory, character device, block device, fifo socket or symbolic link.
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The stream offset of the (first) header. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The tar header. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The object info with unix attributes. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync/** Pointer to a tar filesystem stream base object. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Tar file represented as a VFS I/O stream.
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The basic tar object data. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The number of bytes in the file. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The current file position. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The number of padding bytes following the file. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** Set if we've reached the end of the file. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The input I/O stream. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync/** Pointer to a the private data of a tar file I/O stream. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Tar filesystem stream private data.
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The input I/O stream. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The current object (referenced). */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** Pointer to the private data if hVfsCurObj is representing a file. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The start offset. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** The offset of the next header. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** Set if we've reached the end of the stream. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** Set if we've encountered a fatal error. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync/** Pointer to a the private data of a tar filesystem stream. */
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Checks if the TAR header is in the ustar format.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @returns true / false.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @param pTar The TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncDECLINLINE(bool) rtZipTarHdrIsUstar(PCRTZIPTARHDR pTar)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Checks if the TAR header is in the ustar format and has a regular file type.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @returns true / false.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pTar The TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncDECLINLINE(bool) rtZipTarHdrIsRegularUstar(PCRTZIPTARHDR pTar)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Checks if the TAR header includes a posix user name field.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @returns true / false.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pTar The TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncDECLINLINE(bool) rtZipTarHdrHasPosixUserName(PCRTZIPTARHDR pTar)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Checks if the TAR header includes a posix group name field.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @returns true / false.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pTar The TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncDECLINLINE(bool) rtZipTarHdrHasPosixGroupName(PCRTZIPTARHDR pTar)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Checks if the TAR header includes a posix compatible path prefix field.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @returns true / false.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pTar The TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncDECLINLINE(bool) rtZipTarHdrHasPrefix(PCRTZIPTARHDR pTar)
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * Converts a numeric header field to the C native type.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * @returns IPRT status code.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * @param pszField The TAR header field.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * @param cchField The length of the field.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * @param fOctalOnly Must be octal.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync * @param pi64 Where to store the value.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsyncstatic int rtZipTarHdrFieldToNum(const char *pszField, size_t cchField, bool fOctalOnly, int64_t *pi64)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Skip leading zeros, saving a few slower loops below.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Convert octal digits.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Was it terminated correctly?
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync /** @todo implement base-256 encoded fields. */
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Calculates the tar header checksums and detects if it's all zeros.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @returns true if all zeros, false if not.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @param pHdr The header to checksum.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @param pi32Unsigned Where to store the checksum calculated using
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * unsigned chars. This is the one POSIX
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * specifies.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @param pi32Signed Where to store the checksum calculated using
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * signed chars.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @remarks The reason why we calculate the checksum as both signed and unsigned
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * has to do with various the char C type being signed on some hosts
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * and unsigned on others.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsyncstatic bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Sum up the entire header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Check if it's all zeros and replace the chksum field with spaces.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Posix.chksum);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync i32Signed += (signed char)' ' * sizeof(pHdr->Posix.chksum);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Validates the TAR header.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * @param pTar The TAR header.
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync * @param penmType Where to return the type of header on success.
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsyncstatic int rtZipTarHdrValidate(PCRTZIPTARHDR pTar, PRTZIPTARTYPE penmType)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Calc the checksum first since this enables us to detect zero headers.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync if (rtZipTarCalcChkSum(pTar, &i32ChkSum, &i32ChkSumSignedAlt))
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Read the checksum field and match the checksums.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync int rc = rtZipTarHdrFieldToNum(pTar->Posix.chksum, sizeof(pTar->Posix.chksum), true /*fOctalOnly*/, &i64HdrChkSum);
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync && i32ChkSumSignedAlt != i64HdrChkSum) /** @todo test this */
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync * Detect the tar type.
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync * Perform some basic checks.
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync /** @todo more/less? */
0bb0c0c0e3f9e5fdb3e745715dde1af951c04998vboxsync /** @todo People claim some (older and newer buggy) tar stores dirs as regular files with a trailing slash. */
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync const char *pchEnd = RTStrEnd(&pTar->Posix.name[0], sizeof(pTar->Posix.name));
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync pchEnd = pchEnd ? pchEnd - 1 : &pTar->Posix.name[sizeof(pTar->Posix.name) - 1];
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Translate a TAR header to an IPRT object info structure with additional UNIX
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * attributes.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * This completes the validation done by rtZipTarHdrValidate.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @returns VINF_SUCCESS if valid, appropriate VERR_TAR_XXX if not.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pTar The TAR header (input).
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @param pObjInfo The object info structure (output).
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic int rtZipTarHdrToFsObjInfo(PCRTZIPTARHDR pTar, PRTFSOBJINFO pObjInfo)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Zap the whole structure, this takes care of unused space in the union.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Convert the tar field in RTFSOBJINFO order.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync rc = rtZipTarHdrFieldToNum(a_Field, sizeof(a_Field), false /*fOctalOnly*/, &i64Tmp); \
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync } while (0)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(pObjInfo->cbObject, pTar->Posix.size);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync pObjInfo->cbAllocated = RT_ALIGN_64(pObjInfo->cbObject, 512);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(c64SecModTime, pTar->Posix.mtime);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync RTTimeSpecSetSeconds(&pObjInfo->ChangeTime, c64SecModTime);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync RTTimeSpecSetSeconds(&pObjInfo->ModificationTime, c64SecModTime);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync RTTimeSpecSetSeconds(&pObjInfo->AccessTime, c64SecModTime);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync RTTimeSpecSetSeconds(&pObjInfo->BirthTime, c64SecModTime);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync if (c64SecModTime != RTTimeSpecGetSeconds(&pObjInfo->ModificationTime))
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.fMode, pTar->Posix.mode);
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.uid, pTar->Posix.uid);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(pObjInfo->Attr.u.Unix.gid, pTar->Posix.gid);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(uMajor, pTar->Posix.devmajor);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync GET_TAR_NUMERIC_FIELD_RET(uMinor, pTar->Posix.devminor);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync pObjInfo->Attr.u.Unix.Device = RTDEV_MAKE(uMajor, uMinor);
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync if ( uMajor != RTDEV_MAJOR(pObjInfo->Attr.u.Unix.Device)
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync || uMinor != RTDEV_MINOR(pObjInfo->Attr.u.Unix.Device))
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Massage the result a little bit.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync * Also validate some more now that we've got the numbers to work with.
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync fModeType |= RTFS_TYPE_FILE; /* no better idea for now */
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync return VERR_TAR_UNKNOWN_TYPE_FLAG; /* Should've been caught in validate. */
3a1d76f6489a485dfa7e3784c1fa76b4a53c28afvboxsync && (pObjInfo->Attr.fMode & RTFS_TYPE_MASK) != fModeType)
43af8389304c77c3d4db525de8907cb74207c380vboxsync * T h e V F S F i l e s y s t e m S t r e a m B i t s.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * T h e V F S F i l e s y s t e m S t r e a m B i t s.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * T h e V F S F i l e s y s t e m S t r e a m B i t s.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnClose}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssBaseObj_Close(void *pvThis)
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* Currently there is nothing we really have to do here. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssBaseObj_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Copy the desired data.
43af8389304c77c3d4db525de8907cb74207c380vboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
43af8389304c77c3d4db525de8907cb74207c380vboxsync pObjInfo->Attr.u.UnixOwner.uid = pThis->ObjInfo.Attr.u.Unix.uid;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync RTStrCopy(pObjInfo->Attr.u.UnixOwner.szName, sizeof(pObjInfo->Attr.u.UnixOwner.szName), pThis->Hdr.Posix.uname);
43af8389304c77c3d4db525de8907cb74207c380vboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
43af8389304c77c3d4db525de8907cb74207c380vboxsync pObjInfo->Attr.u.UnixGroup.gid = pThis->ObjInfo.Attr.u.Unix.gid;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync RTStrCopy(pObjInfo->Attr.u.UnixGroup.szName, sizeof(pObjInfo->Attr.u.UnixGroup.szName), pThis->Hdr.Posix.gname);
43af8389304c77c3d4db525de8907cb74207c380vboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Tar filesystem base object operations.
43af8389304c77c3d4db525de8907cb74207c380vboxsync "TarFsStream::Obj",
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnClose}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_Close(void *pvThis)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync return rtZipTarFssBaseObj_QueryInfo(&pThis->BaseObj, pObjInfo, enmAddAttr);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Reads one segment.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @returns IPRT status code.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @param pThis The instance data.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @param pvBuf Where to put the read bytes.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @param cbToRead The number of bytes to read.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @param fBlocking Whether to block or not.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @param pcbRead Where to store the number of bytes actually read.
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic int rtZipTarFssIos_ReadOneSeg(PRTZIPTARIOSTREAM pThis, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Fend of reads beyond the end of the stream here.
43af8389304c77c3d4db525de8907cb74207c380vboxsync uint64_t cbLeft = (uint64_t)(pThis->cbFile - pThis->offFile);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Do the reading.
43af8389304c77c3d4db525de8907cb74207c380vboxsync int rc = RTVfsIoStrmRead(pThis->hVfsIos, pvBuf, cbToRead, fBlocking, pcbRead);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnRead}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_Read(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync rc = rtZipTarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[0].pvSeg, pSgBuf->paSegs[0].cbSeg, fBlocking, pcbRead);
43af8389304c77c3d4db525de8907cb74207c380vboxsync for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
43af8389304c77c3d4db525de8907cb74207c380vboxsync rc = rtZipTarFssIos_ReadOneSeg(pThis, pSgBuf->paSegs[iSeg].pvSeg, pSgBuf->paSegs[iSeg].cbSeg, fBlocking, pcbReadSeg);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnWrite}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_Write(void *pvThis, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* Cannot write to a read-only I/O stream. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync NOREF(pvThis); NOREF(off); NOREF(pSgBuf); NOREF(fBlocking); NOREF(pcbWritten);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnFlush}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_Flush(void *pvThis)
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* It's a read only stream, nothing dirty to flush. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnPollOne}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_PollOne(void *pvThis, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* When we've reached the end, read will be set to indicate it. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync int rc = RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, 0, fIntr, pfRetEvents);
43af8389304c77c3d4db525de8907cb74207c380vboxsync return RTVfsIoStrmPoll(pThis->hVfsIos, fEvents, cMillies, fIntr, pfRetEvents);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSIOSTREAMOPS,pfnTell}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFssIos_Tell(void *pvThis, PRTFOFF poffActual)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARIOSTREAM pThis = (PRTZIPTARIOSTREAM)pvThis;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Tar I/O stream operations.
43af8389304c77c3d4db525de8907cb74207c380vboxsync { /* Obj */
43af8389304c77c3d4db525de8907cb74207c380vboxsync "TarFsStream::IoStream",
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSOBJOPS,pfnClose}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_Close(void *pvThis)
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync return rtZipTarFssBaseObj_QueryInfo(pThis, pObjInfo, enmAddAttr);
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsyncstatic DECLCALLBACK(int) rtZipTarFssSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync return RTStrCopy(pszTarget, cbTarget, pThis->Hdr.Posix.linkname);
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Tar symbolic (and hardlink) operations.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync { /* Obj */
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync "TarFsStream::Symlink",
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync { /* ObjSet */
1c434bf12564eb5a885b3f7e230b7638955004cevboxsync RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet),
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnClose}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFss_Close(void *pvThis)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFss_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* Take the lazy approach here, with the sideffect of providing some info
43af8389304c77c3d4db525de8907cb74207c380vboxsync that is actually kind of useful. */
43af8389304c77c3d4db525de8907cb74207c380vboxsync return RTVfsIoStrmQueryInfo(pThis->hVfsIos, pObjInfo, enmAddAttr);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * @interface_method_impl{RTVFSFSSTREAMOPS,pfnNext}
43af8389304c77c3d4db525de8907cb74207c380vboxsyncstatic DECLCALLBACK(int) rtZipTarFss_Next(void *pvThis, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
43af8389304c77c3d4db525de8907cb74207c380vboxsync PRTZIPTARFSSTREAM pThis = (PRTZIPTARFSSTREAM)pvThis;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Dispense with the current object.
43af8389304c77c3d4db525de8907cb74207c380vboxsync pThis->pCurIosData->offFile = pThis->pCurIosData->cbFile;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Check if we've already reached the end in some way.
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Make sure the input stream is in the right place.
43af8389304c77c3d4db525de8907cb74207c380vboxsync while ( off >= 0
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync int rc = RTVfsIoStrmSkip(pThis->hVfsIos, pThis->offNextHdr - off);
43af8389304c77c3d4db525de8907cb74207c380vboxsync /** @todo Ignore if we're at the end of the stream? */
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Read the next header.
43af8389304c77c3d4db525de8907cb74207c380vboxsync int rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Validate the header and convert to binary object info.
cf9045d402be1e8b7344a439eaefe2ca4c2b53d3vboxsync * We pick up the start of the zero headers here in the failure path.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync int rc2 = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
cf9045d402be1e8b7344a439eaefe2ca4c2b53d3vboxsync /* Just drain the stream because blocksize may dictate that
cf9045d402be1e8b7344a439eaefe2ca4c2b53d3vboxsync there is a whole bunch of stuff comming up. */
cf9045d402be1e8b7344a439eaefe2ca4c2b53d3vboxsync rc = RTVfsIoStrmRead(pThis->hVfsIos, &Hdr, sizeof(Hdr), true /*fBlocking*/, &cbRead);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Create an object of the appropriate type.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Files are represented by a VFS I/O stream.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
cf9045d402be1e8b7344a439eaefe2ca4c2b53d3vboxsync pIosData->cbPadding = Info.cbAllocated - Info.cbObject;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync pThis->offNextHdr += pIosData->cbFile + pIosData->cbPadding;
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * We represent hard links using a symbolic link object. This fits
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * best with the way TAR stores it and there is currently no better
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * fitting VFS type alternative.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * All other objects are repesented using a VFS base object since they
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * carry no data streams (unless some tar extension implements extended
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * attributes / alternative streams).
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync * Set the return data and we're done.
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync *ppszName = RTStrDupN(Hdr.Posix.name, sizeof(Hdr.Posix.name));
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsync rc = *ppszName ? VINF_SUCCESS : VERR_NO_STR_MEMORY;
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Tar filesystem stream operations.
43af8389304c77c3d4db525de8907cb74207c380vboxsync { /* Obj */
43af8389304c77c3d4db525de8907cb74207c380vboxsync "TarFsStream",
1e7030f54deae0a8aa27817ab26c5d6d6c246541vboxsyncRTDECL(int) RTZipTarFsStreamFromIoStream(RTVFSIOSTREAM hVfsIosIn, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Input validation.
43af8389304c77c3d4db525de8907cb74207c380vboxsync RTFOFF const offStart = RTVfsIoStrmTell(hVfsIosIn);
43af8389304c77c3d4db525de8907cb74207c380vboxsync AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
43af8389304c77c3d4db525de8907cb74207c380vboxsync * Retain the input stream and create a new filesystem stream handle.
4152e1d3f89dc5e2319a53c242e8e7cfcdf3726evboxsync int rc = RTVfsNewFsStream(&rtZipTarFssOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, &hVfsFss, (void **)&pThis);
43af8389304c77c3d4db525de8907cb74207c380vboxsync /* Don't check if it's a TAR stream here, do that in the
43af8389304c77c3d4db525de8907cb74207c380vboxsync rtZipTarFss_Next. */