summaryrefslogtreecommitdiffstats
path: root/generic/tclZipfs.c
diff options
context:
space:
mode:
authorgriffin <briang42@easystreet.net>2021-11-04 17:52:22 (GMT)
committergriffin <briang42@easystreet.net>2021-11-04 17:52:22 (GMT)
commitc6971d961df38b5e6585ab4aef66b59a1631b956 (patch)
tree55a330f2743c899c28092e805c03aa6e2af636ef /generic/tclZipfs.c
parent52e7c8c7c41e9ce16cfaf2ea5923c61a6c12a606 (diff)
parent0652bd43d5031f22fe2ea78713a7d788c23dabc2 (diff)
downloadtcl-c6971d961df38b5e6585ab4aef66b59a1631b956.zip
tcl-c6971d961df38b5e6585ab4aef66b59a1631b956.tar.gz
tcl-c6971d961df38b5e6585ab4aef66b59a1631b956.tar.bz2
Merge 8.7
Diffstat (limited to 'generic/tclZipfs.c')
-rw-r--r--generic/tclZipfs.c30
1 files changed, 22 insertions, 8 deletions
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index ba63f01..566987b 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -1179,11 +1179,11 @@ ZipFSFindTOC(
int needZip,
ZipFile *zf)
{
- size_t i;
+ size_t i, minoff;
const unsigned char *p, *q;
const unsigned char *start = zf->data;
const unsigned char *end = zf->data + zf->length;
-
+
/*
* Scan backwards from the end of the file for the signature. This is
* necessary because ZIP archives aren't the only things that get tagged
@@ -1237,6 +1237,8 @@ ZipFSFindTOC(
q = zf->data + ZipReadInt(start, end, p + ZIP_CENTRAL_DIRSTART_OFFS);
p -= ZipReadInt(start, end, p + ZIP_CENTRAL_DIRSIZE_OFFS);
+ zf->baseOffset = zf->passOffset = (p>q) ? p - q : 0;
+ zf->directoryOffset = q - zf->data + zf->baseOffset;
if ((p < q) || (p < zf->data) || (p > zf->data + zf->length)
|| (q < zf->data) || (q > zf->data + zf->length)) {
if (!needZip) {
@@ -1252,11 +1254,11 @@ ZipFSFindTOC(
* Read the central directory.
*/
- zf->baseOffset = zf->passOffset = p - q;
- zf->directoryOffset = p - zf->data;
q = p;
+ minoff = zf->length;
for (i = 0; i < zf->numFiles; i++) {
int pathlen, comlen, extra;
+ size_t localhdr_off = zf->length;
if (q + ZIP_CENTRAL_HEADER_LEN > end) {
ZIPFS_ERROR(interp, "wrong header length");
@@ -1271,16 +1273,27 @@ ZipFSFindTOC(
pathlen = ZipReadShort(start, end, q + ZIP_CENTRAL_PATHLEN_OFFS);
comlen = ZipReadShort(start, end, q + ZIP_CENTRAL_FCOMMENTLEN_OFFS);
extra = ZipReadShort(start, end, q + ZIP_CENTRAL_EXTRALEN_OFFS);
+ localhdr_off = ZipReadInt(start, end, q + ZIP_CENTRAL_LOCALHDR_OFFS);
+ if (ZipReadInt(start, end, zf->data + zf->baseOffset + localhdr_off) != ZIP_LOCAL_HEADER_SIG) {
+ ZIPFS_ERROR(interp, "Failed to find local header");
+ ZIPFS_ERROR_CODE(interp, "LCL_HDR");
+ goto error;
+ }
+ if (localhdr_off < minoff) {
+ minoff = localhdr_off;
+ }
q += pathlen + comlen + extra + ZIP_CENTRAL_HEADER_LEN;
}
+ zf->passOffset = minoff + zf->baseOffset;
+
/*
* If there's also an encoded password, extract that too (but don't decode
* yet).
*/
- q = zf->data + zf->baseOffset;
- if ((zf->baseOffset >= 6) &&
+ q = zf->data + zf->passOffset;
+ if ((zf->passOffset >= 6) && (start < q-4) &&
(ZipReadInt(start, end, q - 4) == ZIP_PASSWORD_END_SIG)) {
const unsigned char *passPtr;
@@ -1292,6 +1305,7 @@ ZipFSFindTOC(
zf->passOffset -= i ? (5 + i) : 0;
}
}
+
return TCL_OK;
error:
@@ -3406,7 +3420,7 @@ SerializeCentralDirectoryEntry(
ZipWriteShort(start, end, buf + ZIP_CENTRAL_IATTR_OFFS, 0);
ZipWriteInt(start, end, buf + ZIP_CENTRAL_EATTR_OFFS, 0);
ZipWriteInt(start, end, buf + ZIP_CENTRAL_LOCALHDR_OFFS,
- z->offset - dataStartOffset);
+ z->offset);
}
static void
@@ -3433,7 +3447,7 @@ SerializeCentralDirectorySuffix(
ZipWriteInt(start, end, buf + ZIP_CENTRAL_DIRSIZE_OFFS,
suffixStartOffset - directoryStartOffset);
ZipWriteInt(start, end, buf + ZIP_CENTRAL_DIRSTART_OFFS,
- directoryStartOffset - dataStartOffset);
+ directoryStartOffset);
ZipWriteShort(start, end, buf + ZIP_CENTRAL_COMMENTLEN_OFFS, 0);
}