summaryrefslogtreecommitdiffstats
path: root/generic/tclZipfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclZipfs.c')
-rw-r--r--generic/tclZipfs.c65
1 files changed, 41 insertions, 24 deletions
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index 92a39e4..673c9e6 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -4698,18 +4698,16 @@ InitWritableChannel(
*/
info->numBytes = 0;
+ z->crc32 = 0; /* Truncated, CRC no longer applicable */
} else if (z->data) {
/*
* Already got uncompressed data.
*/
+ if (z->numBytes > (int) info->maxWrite)
+ goto tooBigError;
- unsigned int j = z->numBytes;
-
- if (j > info->maxWrite) {
- j = info->maxWrite;
- }
- memcpy(info->ubuf, z->data, j);
- info->numBytes = j;
+ memcpy(info->ubuf, z->data, z->numBytes);
+ info->numBytes = z->numBytes;
} else {
/*
* Need to uncompress the existing data.
@@ -4767,39 +4765,53 @@ InitWritableChannel(
}
err = inflate(&stream, Z_SYNC_FLUSH);
inflateEnd(&stream);
- if ((err == Z_STREAM_END)
- || ((err == Z_OK) && (stream.avail_in == 0))) {
- if (cbuf) {
- memset(info->keys, 0, sizeof(info->keys));
- ckfree(cbuf);
- }
- return TCL_OK;
+ if ((err != Z_STREAM_END) &&
+ ((err != Z_OK) || (stream.avail_in != 0))) {
+ goto corruptionError;
+ }
+ /* Even if decompression succeeded, counts should be as expected */
+ if ((int) stream.total_out != z->numBytes)
+ goto corruptionError;
+ info->numBytes = z->numBytes;
+ if (cbuf) {
+ ckfree(cbuf);
}
- goto corruptionError;
} else if (z->isEncrypted) {
/*
* Need to decrypt some otherwise-simple stored data.
*/
-
- for (i = 0; i < z->numBytes - 12; i++) {
+ if (z->numCompressedBytes <= 12 ||
+ (z->numCompressedBytes - 12) != z->numBytes)
+ goto corruptionError;
+ int len = z->numCompressedBytes - 12;
+ for (i = 0; i < len; i++) {
ch = zbuf[i];
info->ubuf[i] = zdecode(info->keys, crc32tab, ch);
}
- } else {
+ info->numBytes = len;
+ }
+ else {
/*
* Simple stored data. Copy into our working buffer.
*/
-
memcpy(info->ubuf, zbuf, z->numBytes);
+ info->numBytes = z->numBytes;
}
memset(info->keys, 0, sizeof(info->keys));
}
+
+ assert(info->numBytes == 0 || (int) info->numBytes == z->numBytes);
return TCL_OK;
memoryError:
ZIPFS_MEM_ERROR(interp);
goto error_cleanup;
+ tooBigError:
+ ZIPFS_ERROR(interp, "file size exceeds max writable");
+ ZIPFS_ERROR_CODE(interp, "TOOBIG");
+ goto error_cleanup;
+
corruptionError:
if (cbuf) {
memset(info->keys, 0, sizeof(info->keys));
@@ -4927,6 +4939,9 @@ InitReadableChannel(
&& ((err != Z_OK) || (stream.avail_in != 0))) {
goto corruptionError;
}
+ /* Even if decompression succeeded, counts should be as expected */
+ if ((int) stream.total_out != z->numBytes)
+ goto corruptionError;
if (ubuf) {
info->isEncrypted = 0;
@@ -4941,7 +4956,8 @@ InitReadableChannel(
* Decode encrypted but uncompressed file, since we support Tcl_Seek()
* on it, and it can be randomly accessed later.
*/
-
+ if (z->numCompressedBytes <= 12 || (z->numCompressedBytes - 12) != z->numBytes)
+ goto corruptionError;
len = z->numCompressedBytes - 12;
ubuf = (unsigned char *) attemptckalloc(len);
if (ubuf == NULL) {
@@ -5092,14 +5108,14 @@ ZipFSOpenFileChannelProc(
int mode,
TCL_UNUSED(int) /* permissions */)
{
- int trunc = (mode & O_TRUNC) != 0;
- int wr = (mode & (O_WRONLY | O_RDWR)) != 0;
-
pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
if (!pathPtr) {
return NULL;
}
+ int trunc = (mode & O_TRUNC) != 0;
+ int wr = (mode & (O_WRONLY | O_RDWR)) != 0;
+
/*
* Check for unsupported modes.
*/
@@ -5108,7 +5124,8 @@ ZipFSOpenFileChannelProc(
Tcl_SetErrno(EACCES);
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "write access not supported: %s",
+ "%s not supported: %s",
+ mode & O_APPEND ? "append mode" : "write access",
Tcl_PosixError(interp)));
}
return NULL;