Skip to content

Commit

Permalink
Fix [00018ec7a0], [f91ee30d33], [23dd83ce7c] - zipfs r+, w+ modes, ze…
Browse files Browse the repository at this point in the history
…ro byte allocation
  • Loading branch information
apnadkarni committed Sep 27, 2023
2 parents 5f54c3f + f2701a0 commit fcaf388
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 87 deletions.
167 changes: 98 additions & 69 deletions generic/tclZipfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1551,8 +1551,10 @@ ZipFSOpenArchive(
ZIPFS_POSIX_ERROR(interp, "seek error");
goto error;
}
if ((zf->length - ZIP_CENTRAL_END_LEN)
> (64 * 1024 * 1024 - ZIP_CENTRAL_END_LEN)) {
/* What's the magic about 64 * 1024 * 1024 ? */
if ((zf->length <= ZIP_CENTRAL_END_LEN) ||
(zf->length - ZIP_CENTRAL_END_LEN) >
(64 * 1024 * 1024 - ZIP_CENTRAL_END_LEN)) {
ZIPFS_ERROR(interp, "illegal file size");
ZIPFS_ERROR_CODE(interp, "FILE_SIZE");
goto error;
Expand Down Expand Up @@ -2265,7 +2267,15 @@ TclZipfs_MountBuffer(

/*
* Have both a mount point and data to mount there.
* What's the magic about 64 * 1024 * 1024 ?
*/
if ((datalen <= ZIP_CENTRAL_END_LEN) ||
(datalen - ZIP_CENTRAL_END_LEN) >
(64 * 1024 * 1024 - ZIP_CENTRAL_END_LEN)) {
ZIPFS_ERROR(interp, "illegal file size");
ZIPFS_ERROR_CODE(interp, "FILE_SIZE");
return TCL_ERROR;
}

zf = AllocateZipFile(interp, strlen(mountPoint));
if (!zf) {
Expand Down Expand Up @@ -4205,26 +4215,38 @@ ZipChannelClose(
memset(info->keys, 0, sizeof(info->keys));
}
if (info->isWriting) {
/*
* Copy channel data back into original file in archive.
* TODO - there seems to be no locking here to protect access from
* multiple threads. The channel (info) may be thread specific (?)
* but the ZipEntry is not afaict
*/
ZipEntry *z = info->zipEntryPtr;
assert(info->ubufToFree && info->ubuf);
unsigned char *newdata =
(unsigned char *)attemptckrealloc(info->ubufToFree, info->numRead);

if (newdata) {
info->ubufToFree = NULL;/* Now newdata! */
info->ubuf = NULL;
if (z->data) {
ckfree(z->data);
}
z->data = newdata;
z->numBytes = z->numCompressedBytes = info->numBytes;
z->compressMethod = ZIP_COMPMETH_STORED;
z->timestamp = time(NULL);
z->isDirectory = 0;
z->isEncrypted = 0;
z->offset = 0;
z->crc32 = 0;
unsigned char *newdata;
newdata = (unsigned char *)attemptckrealloc(
info->ubufToFree,
info->numBytes ? info->numBytes : 1); /* Bug [23dd83ce7c] */
if (newdata == NULL) {
/* Could not reallocate, keep existing buffer */
newdata = info->ubufToFree;
}
info->ubufToFree = NULL; /* Now newdata! */
info->ubuf = NULL;

/* Replace old content */
if (z->data) {
ckfree(z->data);
}
z->data = newdata; /* May be NULL */
z->numBytes = z->numCompressedBytes = info->numBytes;
assert(z->data || z->numBytes == 0);
z->compressMethod = ZIP_COMPMETH_STORED;
z->timestamp = time(NULL);
z->isDirectory = 0;
z->isEncrypted = 0;
z->offset = 0;
z->crc32 = 0;
}
WriteLock();
info->zipFilePtr->numOpen--;
Expand Down Expand Up @@ -4513,14 +4535,27 @@ static Tcl_Channel
ZipChannelOpen(
Tcl_Interp *interp, /* Current interpreter. */
char *filename, /* What are we opening. */
int wr, /* True if we're opening in write mode. */
int trunc) /* True if we're opening in truncate mode. */
int mode) /* O_WRONLY O_RDWR O_TRUNC flags */
{
ZipEntry *z;
ZipChannel *info;
int flags = 0;
char cname[128];

int wr = (mode & (O_WRONLY | O_RDWR)) != 0;

/* Check for unsupported modes. */

if ((mode & O_APPEND) || ((ZipFS.wrmax <= 0) && wr)) {
Tcl_SetErrno(EACCES);
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s not supported: %s",
mode & O_APPEND ? "append mode" : "write access",
Tcl_PosixError(interp)));
}
return NULL;
}
/*
* Is the file there?
*/
Expand Down Expand Up @@ -4564,19 +4599,33 @@ ZipChannelOpen(
ZIPFS_ERROR_CODE(interp, "COMP_METHOD");
goto error;
}
if (!trunc) {
flags |= TCL_READABLE;
if (z->isEncrypted && (z->zipFilePtr->passBuf[0] == 0)) {
ZIPFS_ERROR(interp, "decryption failed");
ZIPFS_ERROR_CODE(interp, "DECRYPT");
goto error;
} else if (wr && !z->data && (z->numBytes > ZipFS.wrmax)) {
ZIPFS_ERROR(interp, "file too large");
ZIPFS_ERROR_CODE(interp, "FILE_SIZE");
if (wr) {
if ((mode & O_TRUNC) == 0 && !z->data && (z->numBytes > ZipFS.wrmax)) {
Tcl_SetErrno(EFBIG);
ZIPFS_POSIX_ERROR(interp, "file size exceeds max writable");
goto error;
}
} else {
flags = TCL_WRITABLE;
if (mode & O_RDWR)
flags |= TCL_READABLE;
} else {
/* Read-only */
flags |= TCL_READABLE;
}
if (flags & TCL_READABLE) {
if (z->isEncrypted) {
if (z->numCompressedBytes < 12) {
ZIPFS_ERROR(interp, "decryption failed: truncated decryption header");
ZIPFS_ERROR_CODE(interp, "DECRYPT");
goto error;

}
if (z->zipFilePtr->passBuf[0] == 0) {
ZIPFS_ERROR(interp, "decryption failed - no password provided");
ZIPFS_ERROR_CODE(interp, "DECRYPT");
goto error;
}
}
}

info = AllocateZipChannel(interp);
Expand All @@ -4586,31 +4635,23 @@ ZipChannelOpen(
info->zipFilePtr = z->zipFilePtr;
info->zipEntryPtr = z;
if (wr) {
/*
* Set up a writable channel.
*/
/* Set up a writable channel. */

flags |= TCL_WRITABLE;
if (InitWritableChannel(interp, info, z, trunc) == TCL_ERROR) {
if (InitWritableChannel(interp, info, z, mode & O_TRUNC) == TCL_ERROR) {
ckfree(info);
goto error;
}
} else if (z->data) {
/*
* Set up a readable channel for direct data.
*/
/* Set up a readable channel for direct data. */

flags |= TCL_READABLE;
info->numBytes = z->numBytes;
info->ubuf = z->data;
info->ubufToFree = NULL; /* Not dynamically allocated */
}
else {
} else {
/*
* Set up a readable channel.
*/

flags |= TCL_READABLE;
if (InitReadableChannel(interp, info, z) == TCL_ERROR) {
ckfree(info);
goto error;
Expand Down Expand Up @@ -4689,11 +4730,13 @@ InitWritableChannel(
info->isWriting = 1;
info->maxWrite = ZipFS.wrmax;

info->ubufToFree = (unsigned char *) attemptckalloc(info->maxWrite);
info->ubufToFree =
(unsigned char *)attemptckalloc(info->maxWrite ? info->maxWrite : 1);
info->ubuf = info->ubufToFree;
if (!info->ubuf) {
goto memoryError;
}
/* TODO - why is the memset necessary? Not cheap for default maxWrite. */
memset(info->ubuf, 0, info->maxWrite);

if (trunc) {
Expand Down Expand Up @@ -4749,8 +4792,11 @@ InitWritableChannel(
if (z->isEncrypted) {
unsigned int j;

/* Min length 12 for keys should already been checked. */
assert(stream.avail_in >= 12);

stream.avail_in -= 12;
cbuf = (unsigned char *) attemptckalloc(stream.avail_in);
cbuf = (unsigned char *) attemptckalloc(stream.avail_in ? stream.avail_in : 1);
if (!cbuf) {
goto memoryError;
}
Expand Down Expand Up @@ -4812,8 +4858,8 @@ InitWritableChannel(
goto error_cleanup;

tooBigError:
ZIPFS_ERROR(interp, "file size exceeds max writable");
ZIPFS_ERROR_CODE(interp, "TOOBIG");
Tcl_SetErrno(EFBIG);
ZIPFS_POSIX_ERROR(interp, "file size exceeds max writable");
goto error_cleanup;

corruptionError:
Expand Down Expand Up @@ -4906,8 +4952,9 @@ InitReadableChannel(
stream.opaque = Z_NULL;
stream.avail_in = z->numCompressedBytes;
if (info->isEncrypted) {
assert(stream.avail_in >= 12);
stream.avail_in -= 12;
ubuf = (unsigned char *) attemptckalloc(stream.avail_in);
ubuf = (unsigned char *) attemptckalloc(stream.avail_in ? stream.avail_in : 1);
if (!ubuf) {
goto memoryError;
}
Expand All @@ -4921,7 +4968,7 @@ InitReadableChannel(
stream.next_in = info->ubuf;
}
info->ubufToFree = (unsigned char *)
attemptckalloc(info->numBytes);
attemptckalloc(info->numBytes ? info->numBytes : 1);
info->ubuf = info->ubufToFree;
stream.next_out = info->ubuf;
if (!info->ubuf) {
Expand Down Expand Up @@ -5117,27 +5164,9 @@ ZipFSOpenFileChannelProc(
return NULL;
}

int trunc = (mode & O_TRUNC) != 0;
int wr = (mode & (O_WRONLY | O_RDWR)) != 0;

/*
* Check for unsupported modes.
*/

if ((mode & O_APPEND) || ((ZipFS.wrmax <= 0) && wr)) {
Tcl_SetErrno(EACCES);
if (interp) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"%s not supported: %s",
mode & O_APPEND ? "append mode" : "write access",
Tcl_PosixError(interp)));
}
return NULL;
}

return ZipChannelOpen(interp, Tcl_GetString(pathPtr), wr, trunc);
return ZipChannelOpen(interp, Tcl_GetString(pathPtr), mode);
}


/*
*-------------------------------------------------------------------------
*
Expand Down
Binary file added tests/zipfiles/empty.zip
Binary file not shown.
Loading

0 comments on commit fcaf388

Please sign in to comment.