summaryrefslogtreecommitdiffstats
path: root/generic/tclZipfs.c
diff options
context:
space:
mode:
Diffstat (limited to 'generic/tclZipfs.c')
-rw-r--r--generic/tclZipfs.c227
1 files changed, 153 insertions, 74 deletions
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index 8706d5a..82e125c 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -27,17 +27,55 @@
#define MAP_FILE 0
#endif /* !MAP_FILE */
#define NOBYFOUR
-#define crc32tab crc_table[0]
#ifndef TBLS
#define TBLS 1
#endif
+#if !defined(_WIN32) && !defined(NO_DLFCN_H)
+#include <dlfcn.h>
+#endif
+
+/*
+ * Macros to report errors only if an interp is present.
+ */
+
+#define ZIPFS_ERROR(interp,errstr) \
+ do { \
+ if (interp) { \
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(errstr, -1)); \
+ } \
+ } while (0)
+#define ZIPFS_MEM_ERROR(interp) \
+ do { \
+ if (interp) { \
+ Tcl_SetObjResult(interp, Tcl_NewStringObj( \
+ "out of memory", -1)); \
+ Tcl_SetErrorCode(interp, "TCL", "MALLOC", NULL); \
+ } \
+ } while (0)
+#define ZIPFS_POSIX_ERROR(interp,errstr) \
+ do { \
+ if (interp) { \
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf( \
+ "%s: %s", errstr, Tcl_PosixError(interp))); \
+ } \
+ } while (0)
+#define ZIPFS_ERROR_CODE(interp,errcode) \
+ do { \
+ if (interp) { \
+ Tcl_SetErrorCode(interp, "TCL", "ZIPFS", errcode, NULL); \
+ } \
+ } while (0)
+
+
#ifdef HAVE_ZLIB
#include "zlib.h"
#include "crypt.h"
#include "zutil.h"
#include "crc32.h"
+static const z_crc_t* crc32tab;
+
/*
** We are compiling as part of the core.
** TIP430 style zipfs prefix
@@ -121,38 +159,6 @@
#define DEFAULT_WRITE_MAX_SIZE (2 * 1024 * 1024)
/*
- * Macros to report errors only if an interp is present.
- */
-
-#define ZIPFS_ERROR(interp,errstr) \
- do { \
- if (interp) { \
- Tcl_SetObjResult(interp, Tcl_NewStringObj(errstr, -1)); \
- } \
- } while (0)
-#define ZIPFS_MEM_ERROR(interp) \
- do { \
- if (interp) { \
- Tcl_SetObjResult(interp, Tcl_NewStringObj( \
- "out of memory", -1)); \
- Tcl_SetErrorCode(interp, "TCL", "MALLOC", NULL); \
- } \
- } while (0)
-#define ZIPFS_POSIX_ERROR(interp,errstr) \
- do { \
- if (interp) { \
- Tcl_SetObjResult(interp, Tcl_ObjPrintf( \
- "%s: %s", errstr, Tcl_PosixError(interp))); \
- } \
- } while (0)
-#define ZIPFS_ERROR_CODE(interp,errcode) \
- do { \
- if (interp) { \
- Tcl_SetErrorCode(interp, "TCL", "ZIPFS", errcode, NULL); \
- } \
- } while (0)
-
-/*
* Windows drive letters.
*/
@@ -249,7 +255,7 @@ typedef struct ZipChannel {
* Most are kept in single ZipFS struct. When build with threading support
* this struct is protected by the ZipFSMutex (see below).
*
- * The "fileHash" component is the process wide global table of all known ZIP
+ * The "fileHash" component is the process-wide global table of all known ZIP
* archive members in all mounted ZIP archives.
*
* The "zipHash" components is the process wide global table of all mounted
@@ -304,13 +310,11 @@ static inline int ListMountPoints(Tcl_Interp *interp);
static void SerializeCentralDirectoryEntry(
const unsigned char *start,
const unsigned char *end, unsigned char *buf,
- ZipEntry *z, size_t nameLength,
- long long dataStartOffset);
+ ZipEntry *z, size_t nameLength);
static void SerializeCentralDirectorySuffix(
const unsigned char *start,
const unsigned char *end, unsigned char *buf,
- int entryCount, long long dataStartOffset,
- long long directoryStartOffset,
+ int entryCount, long long directoryStartOffset,
long long suffixStartOffset);
static void SerializeLocalEntryHeader(
const unsigned char *start,
@@ -346,7 +350,9 @@ static int ZipFSLoadFile(Tcl_Interp *interp, Tcl_Obj *path,
static int ZipMapArchive(Tcl_Interp *interp, ZipFile *zf,
void *handle);
static void ZipfsExitHandler(ClientData clientData);
+static void ZipfsMountExitHandler(ClientData clientData);
static void ZipfsSetup(void);
+static void ZipfsFinalize(void);
static int ZipChannelClose(void *instanceData,
Tcl_Interp *interp, int flags);
static Tcl_DriverGetHandleProc ZipChannelGetFile;
@@ -461,7 +467,8 @@ ZipReadInt(
Tcl_Panic("out of bounds read(4): start=%p, end=%p, ptr=%p",
bufferStart, bufferEnd, ptr);
}
- return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+ return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) |
+ ((unsigned int)ptr[3] << 24);
}
static inline unsigned short
@@ -1181,7 +1188,7 @@ 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;
@@ -1239,6 +1246,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) {
@@ -1254,11 +1263,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");
@@ -1273,16 +1282,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;
@@ -1294,6 +1314,7 @@ ZipFSFindTOC(
zf->passOffset -= i ? (5 + i) : 0;
}
}
+
return TCL_OK;
error:
@@ -1613,7 +1634,7 @@ ZipFSCatalogFilesystem(
*/
zf->mountPoint = (char *) Tcl_GetHashKey(&ZipFS.zipHash, hPtr);
- Tcl_CreateExitHandler(ZipfsExitHandler, zf);
+ Tcl_CreateExitHandler(ZipfsMountExitHandler, zf);
zf->mountPointLen = strlen(zf->mountPoint);
zf->nameLength = strlen(zipname);
@@ -1845,6 +1866,7 @@ ZipfsSetup(void)
Tcl_MutexUnlock(&ZipFSMutex);
#endif /* TCL_THREADS */
+ crc32tab = get_crc_table();
Tcl_FSRegister(NULL, &zipfsFilesystem);
Tcl_InitHashTable(&ZipFS.fileHash, TCL_STRING_KEYS);
Tcl_InitHashTable(&ZipFS.zipHash, TCL_STRING_KEYS);
@@ -1855,6 +1877,7 @@ ZipfsSetup(void)
strcpy(ZipFS.fallbackEntryEncoding, ZIPFS_FALLBACK_ENCODING);
ZipFS.utf8 = Tcl_GetEncoding(NULL, "utf-8");
ZipFS.initialized = 1;
+ Tcl_CreateExitHandler(ZipfsExitHandler, NULL);
}
/*
@@ -2178,7 +2201,7 @@ TclZipfs_Unmount(
ckfree(z);
}
ZipFSCloseArchive(interp, zf);
- Tcl_DeleteExitHandler(ZipfsExitHandler, zf);
+ Tcl_DeleteExitHandler(ZipfsMountExitHandler, zf);
ckfree(zf);
unmounted = 1;
@@ -2984,8 +3007,6 @@ ZipFSMkZipOrImg(
Tcl_Channel out;
int pwlen = 0, slen = 0, count, ret = TCL_ERROR, lobjc;
size_t len, i = 0;
- long long dataStartOffset; /* The overall file offset of the start of the
- * data section of the file. */
long long directoryStartOffset;
/* The overall file offset of the start of the
* central directory. */
@@ -3023,7 +3044,7 @@ ZipFSMkZipOrImg(
}
}
Tcl_IncrRefCount(list);
- if (Tcl_ListObjGetElements(interp, list, &lobjc, &lobjv) != TCL_OK) {
+ if (TclListObjGetElementsM(interp, list, &lobjc, &lobjv) != TCL_OK) {
Tcl_DecrRefCount(list);
return TCL_ERROR;
}
@@ -3162,7 +3183,6 @@ ZipFSMkZipOrImg(
*/
Tcl_InitHashTable(&fileHash, TCL_STRING_KEYS);
- dataStartOffset = Tcl_Tell(out);
if (mappingList == NULL && stripPrefix != NULL) {
strip = Tcl_GetStringFromObj(stripPrefix, &slen);
if (!slen) {
@@ -3203,7 +3223,7 @@ ZipFSMkZipOrImg(
name = Tcl_UtfToExternalDString(ZipFS.utf8, z->name, -1, &ds);
len = Tcl_DStringLength(&ds);
SerializeCentralDirectoryEntry(start, end, (unsigned char *) buf,
- z, len, dataStartOffset);
+ z, len);
if ((Tcl_Write(out, buf, ZIP_CENTRAL_HEADER_LEN)
!= ZIP_CENTRAL_HEADER_LEN)
|| ((size_t) Tcl_Write(out, name, len) != len)) {
@@ -3223,7 +3243,7 @@ ZipFSMkZipOrImg(
Tcl_Flush(out);
suffixStartOffset = Tcl_Tell(out);
SerializeCentralDirectorySuffix(start, end, (unsigned char *) buf,
- count, dataStartOffset, directoryStartOffset, suffixStartOffset);
+ count, directoryStartOffset, suffixStartOffset);
if (Tcl_Write(out, buf, ZIP_CENTRAL_END_LEN) != ZIP_CENTRAL_END_LEN) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"write error: %s", Tcl_PosixError(interp)));
@@ -3380,9 +3400,7 @@ SerializeCentralDirectoryEntry(
const unsigned char *end, /* The end of writable memory. */
unsigned char *buf, /* Where to serialize to */
ZipEntry *z, /* The description of what to serialize. */
- size_t nameLength, /* The length of the name. */
- long long dataStartOffset) /* The overall file offset of the start of the
- * data section of the file. */
+ size_t nameLength) /* The length of the name. */
{
ZipWriteInt(start, end, buf + ZIP_CENTRAL_SIG_OFFS,
ZIP_CENTRAL_HEADER_SIG);
@@ -3407,7 +3425,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
@@ -3416,8 +3434,6 @@ SerializeCentralDirectorySuffix(
const unsigned char *end, /* The end of writable memory. */
unsigned char *buf, /* Where to serialize to */
int entryCount, /* The number of entries in the directory */
- long long dataStartOffset, /* The overall file offset of the start of the
- * data section of the file. */
long long directoryStartOffset,
/* The overall file offset of the start of the
* central directory. */
@@ -3434,7 +3450,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);
}
@@ -3904,6 +3920,12 @@ TclZipfs_TclLibrary(void)
if (ZipfsAppHookFindTclInit(dllName) == TCL_OK) {
return Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
}
+#elif !defined(NO_DLFCN_H)
+ Dl_info dlinfo;
+ if (dladdr((const void *)TclZipfs_TclLibrary, &dlinfo) && (dlinfo.dli_fname != NULL)
+ && (ZipfsAppHookFindTclInit(dlinfo.dli_fname) == TCL_OK)) {
+ return Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
+ }
#else
if (ZipfsAppHookFindTclInit(CFG_RUNTIME_LIBDIR "/" CFG_RUNTIME_DLLFILE) == TCL_OK) {
return Tcl_NewStringObj(zipfs_literal_tcl_library, -1);
@@ -5689,6 +5711,8 @@ TclZipfs_Init(
#endif /* HAVE_ZLIB */
}
+#ifdef HAVE_ZLIB
+
#if !defined(STATIC_BUILD)
static int
ZipfsAppHookFindTclInit(
@@ -5730,15 +5754,50 @@ ZipfsAppHookFindTclInit(
static void
ZipfsExitHandler(
+ TCL_UNUSED(ClientData)
+)
+{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ if (ZipFS.initialized != -1) {
+ hPtr = Tcl_FirstHashEntry(&ZipFS.fileHash, &search);
+ if (hPtr == NULL) {
+ ZipfsFinalize();
+ } else {
+ /* ZipFS.fallbackEntryEncoding was already freed by
+ * ZipfsMountExitHandler
+ */
+ }
+ }
+}
+
+static void
+ZipfsFinalize(void) {
+ Tcl_DeleteHashTable(&ZipFS.fileHash);
+ ckfree(ZipFS.fallbackEntryEncoding);
+ ZipFS.initialized = -1;
+}
+
+static void
+ZipfsMountExitHandler(
ClientData clientData)
{
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+
ZipFile *zf = (ZipFile *) clientData;
if (TCL_OK != TclZipfs_Unmount(NULL, zf->mountPoint)) {
Tcl_Panic("tried to unmount busy filesystem");
}
+
+ hPtr = Tcl_FirstHashEntry(&ZipFS.fileHash, &search);
+ if (hPtr == NULL) {
+ ZipfsFinalize();
+ }
+
}
-
+
/*
*-------------------------------------------------------------------------
*
@@ -5749,7 +5808,7 @@ ZipfsExitHandler(
*-------------------------------------------------------------------------
*/
-int
+const char *
TclZipfs_AppHook(
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
int *argcPtr, /* Pointer to argc */
@@ -5763,6 +5822,7 @@ TclZipfs_AppHook(
#endif /* _WIN32 */
{
const char *archive;
+ const char *version = Tcl_InitSubsystems();
#ifdef _WIN32
Tcl_FindExecutable(NULL);
@@ -5805,7 +5865,7 @@ TclZipfs_AppHook(
Tcl_DecrRefCount(vfsInitScript);
if (found == TCL_OK) {
zipfs_literal_tcl_library = ZIPFS_APP_MOUNT "/tcl_library";
- return TCL_OK;
+ return version;
}
}
#ifdef SUPPORT_BUILTIN_ZIP_INSTALL
@@ -5838,7 +5898,7 @@ TclZipfs_AppHook(
if (Tcl_FSAccess(vfsInitScript, F_OK) == 0) {
Tcl_SetStartupScript(vfsInitScript, NULL);
}
- return TCL_OK;
+ return version;
} else if (!TclZipfs_Mount(NULL, ZIPFS_APP_MOUNT, archive, NULL)) {
int found;
Tcl_Obj *vfsInitScript;
@@ -5862,7 +5922,7 @@ TclZipfs_AppHook(
Tcl_DecrRefCount(vfsInitScript);
if (found == TCL_OK) {
zipfs_literal_tcl_library = ZIPFS_APP_MOUNT "/tcl_library";
- return TCL_OK;
+ return version;
}
}
#ifdef _WIN32
@@ -5870,10 +5930,10 @@ TclZipfs_AppHook(
#endif /* _WIN32 */
#endif /* SUPPORT_BUILTIN_ZIP_INSTALL */
}
- return TCL_OK;
+ return version;
}
-#ifndef HAVE_ZLIB
+#else /* !HAVE_ZLIB */
/*
*-------------------------------------------------------------------------
@@ -5888,9 +5948,9 @@ TclZipfs_AppHook(
int
TclZipfs_Mount(
Tcl_Interp *interp, /* Current interpreter. */
- const char *mountPoint, /* Mount point path. */
- const char *zipname, /* Path to ZIP file to mount. */
- const char *passwd) /* Password for opening the ZIP, or NULL if
+ TCL_UNUSED(const char *), /* Mount point path. */
+ TCL_UNUSED(const char *), /* Path to ZIP file to mount. */
+ TCL_UNUSED(const char *)) /* Password for opening the ZIP, or NULL if
* the ZIP is unprotected. */
{
ZIPFS_ERROR(interp, "no zlib available");
@@ -5901,10 +5961,10 @@ TclZipfs_Mount(
int
TclZipfs_MountBuffer(
Tcl_Interp *interp, /* Current interpreter. NULLable. */
- const char *mountPoint, /* Mount point path. */
- unsigned char *data,
- size_t datalen,
- int copy)
+ TCL_UNUSED(const char *), /* Mount point path. */
+ TCL_UNUSED(unsigned char *),
+ TCL_UNUSED(size_t),
+ TCL_UNUSED(int))
{
ZIPFS_ERROR(interp, "no zlib available");
ZIPFS_ERROR_CODE(interp, "NO_ZLIB");
@@ -5914,12 +5974,31 @@ TclZipfs_MountBuffer(
int
TclZipfs_Unmount(
Tcl_Interp *interp, /* Current interpreter. */
- const char *mountPoint) /* Mount point path. */
+ TCL_UNUSED(const char *)) /* Mount point path. */
{
ZIPFS_ERROR(interp, "no zlib available");
ZIPFS_ERROR_CODE(interp, "NO_ZLIB");
return TCL_ERROR;
}
+
+const char *
+TclZipfs_AppHook(
+ TCL_UNUSED(int *), /*argcPtr*/
+#ifdef _WIN32
+ TCL_UNUSED(WCHAR ***)) /* argvPtr */
+#else /* !_WIN32 */
+ TCL_UNUSED(char ***)) /* Pointer to argv */
+#endif /* _WIN32 */
+{
+ return NULL;
+}
+
+Tcl_Obj *
+TclZipfs_TclLibrary(void)
+{
+ return NULL;
+}
+
#endif /* !HAVE_ZLIB */
/*