summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/zip/tar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Runtime/common/zip/tar.cpp')
-rw-r--r--src/VBox/Runtime/common/zip/tar.cpp170
1 files changed, 113 insertions, 57 deletions
diff --git a/src/VBox/Runtime/common/zip/tar.cpp b/src/VBox/Runtime/common/zip/tar.cpp
index cb342d23..e2ced7e6 100644
--- a/src/VBox/Runtime/common/zip/tar.cpp
+++ b/src/VBox/Runtime/common/zip/tar.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -40,6 +40,7 @@
#include <iprt/string.h>
#include "internal/magics.h"
+#include "tar.h"
/******************************************************************************
@@ -85,19 +86,10 @@ typedef union RTTARRECORD
} RTTARRECORD;
AssertCompileSize(RTTARRECORD, 512);
AssertCompileMemberOffset(RTTARRECORD, h.size, 100+8*3);
+AssertCompileMemberSize(RTTARRECORD, h.name, RTTAR_NAME_MAX+1);
/** Pointer to a tar file header. */
typedef RTTARRECORD *PRTTARRECORD;
-
-#if 0 /* not currently used */
-typedef struct RTTARFILELIST
-{
- char *pszFilename;
- RTTARFILELIST *pNext;
-} RTTARFILELIST;
-typedef RTTARFILELIST *PRTTARFILELIST;
-#endif
-
/** Pointer to a tar file handle. */
typedef struct RTTARFILEINTERNAL *PRTTARFILEINTERNAL;
@@ -144,10 +136,22 @@ typedef struct RTTARFILEINTERNAL
uint64_t offCurrent;
/** The open mode. */
uint32_t fOpenMode;
+ /** The link flag. */
+ char linkflag;
} RTTARFILEINTERNAL;
/** Pointer to the internal data of a tar file. */
typedef RTTARFILEINTERNAL *PRTTARFILEINTERNAL;
+#if 0 /* not currently used */
+typedef struct RTTARFILELIST
+{
+ char *pszFilename;
+ RTTARFILELIST *pNext;
+} RTTARFILELIST;
+typedef RTTARFILELIST *PRTTARFILELIST;
+#endif
+
+
/******************************************************************************
* Defined Constants And Macros *
@@ -265,29 +269,59 @@ DECLINLINE(uint64_t) rtTarRecToSize(PRTTARRECORD pRecord)
return (uint64_t)cbSize;
}
-DECLINLINE(int) rtTarCalcChkSum(PRTTARRECORD pRecord, uint32_t *pChkSum)
+/**
+ * Calculates the TAR header checksums and detects if it's all zeros.
+ *
+ * @returns true if all zeros, false if not.
+ * @param pHdr The header to checksum.
+ * @param pi32Unsigned Where to store the checksum calculated using
+ * unsigned chars. This is the one POSIX
+ * specifies.
+ * @param pi32Signed Where to store the checksum calculated using
+ * signed chars.
+ *
+ * @remarks The reason why we calculate the checksum as both signed and unsigned
+ * has to do with various the char C type being signed on some hosts
+ * and unsigned on others.
+ *
+ * @remarks Borrowed from tarvfs.cpp.
+ */
+static bool rtZipTarCalcChkSum(PCRTZIPTARHDR pHdr, int32_t *pi32Unsigned, int32_t *pi32Signed)
{
- uint32_t check = 0;
- uint32_t zero = 0;
- for (size_t i = 0; i < sizeof(RTTARRECORD); ++i)
+ int32_t i32Unsigned = 0;
+ int32_t i32Signed = 0;
+
+ /*
+ * Sum up the entire header.
+ */
+ const char *pch = (const char *)pHdr;
+ const char *pchEnd = pch + sizeof(*pHdr);
+ do
{
- /* Calculate the sum of every byte from the header. The checksum field
- * itself is counted as all blanks. */
- if ( i < RT_UOFFSETOF(RTTARRECORD, h.chksum)
- || i >= RT_UOFFSETOF(RTTARRECORD, h.linkflag))
- check += pRecord->d[i];
- else
- check += ' ';
- /* Additional check if all fields are zero, which indicate EOF. */
- zero += pRecord->d[i];
- }
+ i32Unsigned += *(unsigned char *)pch;
+ i32Signed += *(signed char *)pch;
+ } while (++pch != pchEnd);
- /* EOF? */
- if (!zero)
- return VERR_TAR_END_OF_FILE;
+ /*
+ * Check if it's all zeros and replace the chksum field with spaces.
+ */
+ bool const fZeroHdr = i32Unsigned == 0;
- *pChkSum = check;
- return VINF_SUCCESS;
+ pch = pHdr->Common.chksum;
+ pchEnd = pch + sizeof(pHdr->Common.chksum);
+ do
+ {
+ i32Unsigned -= *(unsigned char *)pch;
+ i32Signed -= *(signed char *)pch;
+ } while (++pch != pchEnd);
+
+ i32Unsigned += (unsigned char)' ' * sizeof(pHdr->Common.chksum);
+ i32Signed += (signed char)' ' * sizeof(pHdr->Common.chksum);
+
+ *pi32Unsigned = i32Unsigned;
+ if (pi32Signed)
+ *pi32Signed = i32Signed;
+ return fZeroHdr;
}
DECLINLINE(int) rtTarReadHeaderRecord(RTFILE hFile, PRTTARRECORD pRecord)
@@ -302,16 +336,16 @@ DECLINLINE(int) rtTarReadHeaderRecord(RTFILE hFile, PRTTARRECORD pRecord)
return rc;
/* Check for data integrity & an EOF record */
- uint32_t check = 0;
- rc = rtTarCalcChkSum(pRecord, &check);
- /* EOF? */
- if (RT_FAILURE(rc))
- return rc;
+ int32_t iUnsignedChksum, iSignedChksum;
+ if (rtZipTarCalcChkSum((PCRTZIPTARHDR)pRecord, &iUnsignedChksum, &iSignedChksum))
+ return VERR_TAR_END_OF_FILE;
/* Verify the checksum */
uint32_t sum;
rc = RTStrToUInt32Full(pRecord->h.chksum, 8, &sum);
- if (RT_SUCCESS(rc) && sum == check)
+ if ( RT_SUCCESS(rc)
+ && ( sum == (uint32_t)iSignedChksum
+ || sum == (uint32_t)iUnsignedChksum) )
{
/* Make sure the strings are zero terminated. */
pRecord->h.name[sizeof(pRecord->h.name) - 1] = 0;
@@ -332,24 +366,27 @@ DECLINLINE(int) rtTarCreateHeaderRecord(PRTTARRECORD pRecord, const char *pszSrc
/** @todo check for field overflows. */
/* Fill the header record */
// RT_ZERO(pRecord); - done by the caller.
- RTStrPrintf(pRecord->h.name, sizeof(pRecord->h.name), "%s", pszSrcName);
- RTStrPrintf(pRecord->h.mode, sizeof(pRecord->h.mode), "%0.7o", fmode);
- RTStrPrintf(pRecord->h.uid, sizeof(pRecord->h.uid), "%0.7o", uid);
- RTStrPrintf(pRecord->h.gid, sizeof(pRecord->h.gid), "%0.7o", gid);
+ /** @todo use RTStrCopy */
+ size_t cb = RTStrPrintf(pRecord->h.name, sizeof(pRecord->h.name), "%s", pszSrcName);
+ if (cb < strlen(pszSrcName))
+ return VERR_BUFFER_OVERFLOW;
+ RTStrPrintf(pRecord->h.mode, sizeof(pRecord->h.mode), "%0.7o", fmode);
+ RTStrPrintf(pRecord->h.uid, sizeof(pRecord->h.uid), "%0.7o", uid);
+ RTStrPrintf(pRecord->h.gid, sizeof(pRecord->h.gid), "%0.7o", gid);
rtTarSizeToRec(pRecord, cbSize);
- RTStrPrintf(pRecord->h.mtime, sizeof(pRecord->h.mtime), "%0.11o", mtime);
+ RTStrPrintf(pRecord->h.mtime, sizeof(pRecord->h.mtime), "%0.11llo", mtime);
RTStrPrintf(pRecord->h.magic, sizeof(pRecord->h.magic), "ustar ");
RTStrPrintf(pRecord->h.uname, sizeof(pRecord->h.uname), "someone");
RTStrPrintf(pRecord->h.gname, sizeof(pRecord->h.gname), "someone");
pRecord->h.linkflag = LF_NORMAL;
/* Create the checksum out of the new header */
- uint32_t uChkSum = 0;
- int rc = rtTarCalcChkSum(pRecord, &uChkSum);
- if (RT_FAILURE(rc))
- return rc;
+ int32_t iUnsignedChksum, iSignedChksum;
+ if (rtZipTarCalcChkSum((PCRTZIPTARHDR)pRecord, &iUnsignedChksum, &iSignedChksum))
+ return VERR_TAR_END_OF_FILE;
+
/* Format the checksum */
- RTStrPrintf(pRecord->h.chksum, sizeof(pRecord->h.chksum), "%0.7o", uChkSum);
+ RTStrPrintf(pRecord->h.chksum, sizeof(pRecord->h.chksum), "%0.7o", iUnsignedChksum);
return VINF_SUCCESS;
}
@@ -1178,7 +1215,7 @@ RTR3DECL(int) RTTarFileSetTime(RTTARFILE hFile, PRTTIMESPEC pTime)
/* Convert the time to an string. */
char szModTime[RT_SIZEOFMEMB(RTTARRECORD, h.mtime)];
- RTStrPrintf(szModTime, sizeof(szModTime), "%0.11o", RTTimeSpecGetSeconds(pTime));
+ RTStrPrintf(szModTime, sizeof(szModTime), "%0.11llo", RTTimeSpecGetSeconds(pTime));
/* Write it directly into the header */
return RTFileWriteAt(pFileInt->pTar->hTarFile,
@@ -1617,14 +1654,23 @@ RTR3DECL(int) RTTarSeekNextFile(RTTAR hTar)
* If not we are somehow busted. */
uint64_t offCur = RTFileTell(pInt->hTarFile);
if (!( pInt->pFileCache->offStart <= offCur
- && offCur < pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
+ && offCur <= pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize))
return VERR_INVALID_STATE;
/* Seek to the next file header. */
uint64_t offNext = RT_ALIGN(pInt->pFileCache->offStart + sizeof(RTTARRECORD) + pInt->pFileCache->cbSize, sizeof(RTTARRECORD));
- rc = RTFileSeek(pInt->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
- if (RT_FAILURE(rc))
- return rc;
+ if (pInt->pFileCache->cbSize != 0)
+ {
+ rc = RTFileSeek(pInt->hTarFile, offNext - offCur, RTFILE_SEEK_CURRENT, NULL);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+ else
+ {
+ /* Else delete the last open file cache. Might be recreated below. */
+ rtDeleteTarFileInternal(pInt->pFileCache);
+ pInt->pFileCache = NULL;
+ }
/* Again check the current filename to fill the cache with the new value. */
return RTTarCurrentFile(hTar, NULL);
@@ -1648,20 +1694,24 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
/* Is there some cached entry? */
if (pInt->pFileCache)
{
- /* Are we still direct behind that header? */
- if (pInt->pFileCache->offStart + sizeof(RTTARRECORD) == RTFileTell(pInt->hTarFile))
+ if (pInt->pFileCache->offStart + sizeof(RTTARRECORD) < RTFileTell(pInt->hTarFile))
+ {
+ /* Else delete the last open file cache. Might be recreated below. */
+ rtDeleteTarFileInternal(pInt->pFileCache);
+ pInt->pFileCache = NULL;
+ }
+ else/* Are we still directly behind that header? */
{
/* Yes, so the streaming can start. Just return the cached file
* structure to the caller. */
*phFile = rtCopyTarFileInternal(pInt->pFileCache);
if (ppszFilename)
*ppszFilename = RTStrDup(pInt->pFileCache->pszFilename);
+ if (pInt->pFileCache->linkflag == LF_DIR)
+ return VINF_TAR_DIR_PATH;
return VINF_SUCCESS;
}
- /* Else delete the last open file cache. Might be recreated below. */
- rtDeleteTarFileInternal(pInt->pFileCache);
- pInt->pFileCache = NULL;
}
PRTTARFILEINTERNAL pFileInt = NULL;
@@ -1679,7 +1729,8 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
/* We support normal files only */
if ( record.h.linkflag == LF_OLDNORMAL
- || record.h.linkflag == LF_NORMAL)
+ || record.h.linkflag == LF_NORMAL
+ || record.h.linkflag == LF_DIR)
{
pFileInt = rtCreateTarFileInternal(pInt, record.h.name, fOpen);
if (!pFileInt)
@@ -1692,11 +1743,16 @@ RTR3DECL(int) RTTarFileOpenCurrentFile(RTTAR hTar, PRTTARFILE phFile, char **pps
pFileInt->cbSize = rtTarRecToSize(&record);
/* The start is -512 from here. */
pFileInt->offStart = RTFileTell(pInt->hTarFile) - sizeof(RTTARRECORD);
+ /* remember the type of a file */
+ pFileInt->linkflag = record.h.linkflag;
/* Copy the new file structure to our cache. */
pInt->pFileCache = rtCopyTarFileInternal(pFileInt);
if (ppszFilename)
*ppszFilename = RTStrDup(pFileInt->pszFilename);
+
+ if (pFileInt->linkflag == LF_DIR)
+ rc = VINF_TAR_DIR_PATH;
}
} while (0);