summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tcl.decls15
-rw-r--r--generic/tclDecls.h14
-rw-r--r--generic/tclStubInit.c1
-rw-r--r--generic/tclZipfs.c493
-rw-r--r--tests/zipfs.test73
5 files changed, 458 insertions, 138 deletions
diff --git a/generic/tcl.decls b/generic/tcl.decls
index 87beab3..8d03db1 100644
--- a/generic/tcl.decls
+++ b/generic/tcl.decls
@@ -2334,8 +2334,11 @@ declare 631 {
# TIP #430
declare 632 {
- int TclZipfs_Mount(Tcl_Interp *interp, const char *zipname, const char *mntpt,
- const char *passwd)
+ int TclZipfs_Mount(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ const char *zipname,
+ const char *passwd)
}
declare 633 {
int TclZipfs_Unmount(Tcl_Interp *interp, const char *zipname)
@@ -2343,6 +2346,14 @@ declare 633 {
declare 634 {
Tcl_Obj *TclZipfs_TclLibrary(void)
}
+declare 635 {
+ int TclZipfs_Mount_Buffer(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ unsigned char *data,
+ size_t datalen,
+ int copy)
+}
##############################################################################
# Define the platform specific public Tcl interface. These functions are only
diff --git a/generic/tclDecls.h b/generic/tclDecls.h
index 8ba9e5c..40fa7e2 100644
--- a/generic/tclDecls.h
+++ b/generic/tclDecls.h
@@ -1839,14 +1839,17 @@ EXTERN Tcl_Channel Tcl_OpenTcpServerEx(Tcl_Interp *interp,
Tcl_TcpAcceptProc *acceptProc,
ClientData callbackData);
/* 632 */
-EXTERN int TclZipfs_Mount(Tcl_Interp *interp,
- const char *zipname, const char *mntpt,
- const char *passwd);
+EXTERN int TclZipfs_Mount(Tcl_Interp *interp, const char *mntpt,
+ const char *zipname, const char *passwd);
/* 633 */
EXTERN int TclZipfs_Unmount(Tcl_Interp *interp,
const char *zipname);
/* 634 */
EXTERN Tcl_Obj * TclZipfs_TclLibrary(void);
+/* 635 */
+EXTERN int TclZipfs_Mount_Buffer(Tcl_Interp *interp,
+ const char *mntpt, unsigned char *data,
+ size_t datalen, int copy);
typedef struct {
const struct TclPlatStubs *tclPlatStubs;
@@ -2514,9 +2517,10 @@ typedef struct TclStubs {
int (*tcl_FSUnloadFile) (Tcl_Interp *interp, Tcl_LoadHandle handlePtr); /* 629 */
void (*tcl_ZlibStreamSetCompressionDictionary) (Tcl_ZlibStream zhandle, Tcl_Obj *compressionDictionaryObj); /* 630 */
Tcl_Channel (*tcl_OpenTcpServerEx) (Tcl_Interp *interp, const char *service, const char *host, unsigned int flags, Tcl_TcpAcceptProc *acceptProc, ClientData callbackData); /* 631 */
- int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *zipname, const char *mntpt, const char *passwd); /* 632 */
+ int (*tclZipfs_Mount) (Tcl_Interp *interp, const char *mntpt, const char *zipname, const char *passwd); /* 632 */
int (*tclZipfs_Unmount) (Tcl_Interp *interp, const char *zipname); /* 633 */
Tcl_Obj * (*tclZipfs_TclLibrary) (void); /* 634 */
+ int (*tclZipfs_Mount_Buffer) (Tcl_Interp *interp, const char *mntpt, unsigned char *data, size_t datalen, int copy); /* 635 */
} TclStubs;
extern const TclStubs *tclStubsPtr;
@@ -3817,6 +3821,8 @@ extern const TclStubs *tclStubsPtr;
(tclStubsPtr->tclZipfs_Unmount) /* 633 */
#define TclZipfs_TclLibrary \
(tclStubsPtr->tclZipfs_TclLibrary) /* 634 */
+#define TclZipfs_Mount_Buffer \
+ (tclStubsPtr->tclZipfs_Mount_Buffer) /* 635 */
#endif /* defined(USE_TCL_STUBS) */
diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c
index fdc8aec..28d26a6 100644
--- a/generic/tclStubInit.c
+++ b/generic/tclStubInit.c
@@ -1616,6 +1616,7 @@ const TclStubs tclStubs = {
TclZipfs_Mount, /* 632 */
TclZipfs_Unmount, /* 633 */
TclZipfs_TclLibrary, /* 634 */
+ TclZipfs_Mount_Buffer, /* 635 */
};
/* !END!: Do not edit above this line. */
diff --git a/generic/tclZipfs.c b/generic/tclZipfs.c
index 5be25c3..b81c58f 100644
--- a/generic/tclZipfs.c
+++ b/generic/tclZipfs.c
@@ -168,6 +168,8 @@ TCL_DECLARE_MUTEX(localtimeMutex)
typedef struct ZipFile {
char *name; /* Archive name */
+ size_t namelen;
+ char is_membuf; /* When true, not a file but a memory buffer */
Tcl_Channel chan; /* Channel handle or NULL */
unsigned char *data; /* Memory mapped or malloc'ed file */
long length; /* Length of memory mapped file */
@@ -186,8 +188,8 @@ typedef struct ZipFile {
#if HAS_DRIVES
int mntdrv; /* Drive letter of mount point */
#endif
- char *mntpt; /* Mount point */
- size_t mntptlen;
+ int mntptlen;
+ char *mntpt; /* Mount point */
} ZipFile;
/*
@@ -325,7 +327,19 @@ static const z_crc_t crc32tab[256] = {
const char *zipfs_literal_tcl_library=NULL;
/* Function prototypes */
-int TclZipfs_Mount(Tcl_Interp *interp, const char *mntpt, const char *zipname, const char *passwd);
+int TclZipfs_Mount(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ const char *zipname,
+ const char *passwd
+);
+int TclZipfs_Mount_Buffer(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ unsigned char *data,
+ size_t datalen,
+ int copy
+);
static int TclZipfs_AppHook_FindTclInit(const char *archive);
static int Zip_FSPathInFilesystemProc(Tcl_Obj *pathPtr, ClientData *clientDataPtr);
static Tcl_Obj *Zip_FSFilesystemPathTypeProc(Tcl_Obj *pathPtr);
@@ -919,6 +933,18 @@ ZipFSLookupMount(char *filename)
static void
ZipFSCloseArchive(Tcl_Interp *interp, ZipFile *zf)
{
+ if(zf->namelen) {
+ free(zf->name); //Allocated by strdup
+ }
+ if(zf->is_membuf==1) {
+ /* Pointer to memory */
+ if (zf->tofree != NULL) {
+ Tcl_Free((char *) zf->tofree);
+ zf->tofree = NULL;
+ }
+ zf->data = NULL;
+ return;
+ }
#if defined(_WIN32) || defined(_WIN64)
if ((zf->data != NULL) && (zf->tofree == NULL)) {
UnmapViewOfFile(zf->data);
@@ -946,7 +972,7 @@ ZipFSCloseArchive(Tcl_Interp *interp, ZipFile *zf)
/*
*-------------------------------------------------------------------------
*
- * ZipFSIndexArchive --
+ * ZipFS_Find_TOC --
*
* This function takes a memory mapped zip file and indexes the contents.
* When "needZip" is zero an embedded ZIP archive in an executable file is accepted.
@@ -961,7 +987,7 @@ ZipFSCloseArchive(Tcl_Interp *interp, ZipFile *zf)
*-------------------------------------------------------------------------
*/
static int
-ZipFSIndexArchive(Tcl_Interp *interp, int needZip, ZipFile *zf)
+ZipFS_Find_TOC(Tcl_Interp *interp, int needZip, ZipFile *zf)
{
int i;
unsigned char *p, *q;
@@ -1034,6 +1060,7 @@ ZipFSIndexArchive(Tcl_Interp *interp, int needZip, ZipFile *zf)
zf->baseoffsp -= i ? (5 + i) : 0;
}
}
+
return TCL_OK;
error:
@@ -1069,7 +1096,8 @@ ZipFSOpenArchive(Tcl_Interp *interp, const char *zipname, int needZip, ZipFile *
{
int i;
ClientData handle;
-
+
+ zf->is_membuf=0;
#if defined(_WIN32) || defined(_WIN64)
zf->data = NULL;
zf->mh = INVALID_HANDLE_VALUE;
@@ -1147,61 +1175,33 @@ ZipFSOpenArchive(Tcl_Interp *interp, const char *zipname, int needZip, ZipFile *
}
#endif
}
- return ZipFSIndexArchive(interp,needZip,zf);
+ return ZipFS_Find_TOC(interp,needZip,zf);
error:
ZipFSCloseArchive(interp, zf);
return TCL_ERROR;
}
-
-static void TclZipfs_C_Init(void) {
- static const Tcl_Time t = { 0, 0 };
- if (!ZipFS.initialized) {
-#ifdef TCL_THREADS
- /*
- * Inflate condition variable.
- */
- Tcl_MutexLock(&ZipFSMutex);
- Tcl_ConditionWait(&ZipFSCond, &ZipFSMutex, &t);
- Tcl_MutexUnlock(&ZipFSMutex);
-#endif
- Tcl_FSRegister(NULL, &zipfsFilesystem);
- Tcl_InitHashTable(&ZipFS.fileHash, TCL_STRING_KEYS);
- Tcl_InitHashTable(&ZipFS.zipHash, TCL_STRING_KEYS);
- ZipFS.initialized = ZipFS.idCount = 1;
- }
-}
-
-
/*
*-------------------------------------------------------------------------
*
- * TclZipfs_Mount --
+ * ZipFSRootNode --
*
- * This procedure is invoked to mount a given ZIP archive file on
- * a given mountpoint with optional ZIP password.
+ * This function generates the root node for a ZIPFS filesystem
*
* Results:
- * A standard Tcl result.
+ * TCL_OK on success, TCL_ERROR otherwise with an error message
+ * placed into the given "interp" if it is not NULL.
*
* Side effects:
- * A ZIP archive file is read, analyzed and mounted, resources are
- * allocated.
- *
*-------------------------------------------------------------------------
*/
-int
-TclZipfs_Mount(
- Tcl_Interp *interp,
- const char *mntpt,
- const char *zipname,
- const char *passwd
-) {
- char *realname, *p;
+static int
+ZipFS_Catalogue_Filesystem(Tcl_Interp *interp, ZipFile *zf0, const char *mntpt, const char *passwd, const char *zipname)
+{
int i, pwlen, isNew;
- ZipFile *zf, zf0;
+ ZipFile *zf;
ZipEntry *z;
Tcl_HashEntry *hPtr;
Tcl_DString ds, dsm, fpBuf;
@@ -1209,58 +1209,8 @@ TclZipfs_Mount(
#if HAS_DRIVES
int drive = 0;
#endif
-
- ReadLock();
- if (!ZipFS.initialized) {
- TclZipfs_C_Init();
- }
- if (mntpt == NULL) {
- Tcl_HashSearch search;
- int ret = TCL_OK;
-
- i = 0;
- hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search);
- while (hPtr != NULL) {
- if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) {
- if (interp != NULL) {
- Tcl_AppendElement(interp, zf->mntpt);
- Tcl_AppendElement(interp, zf->name);
- }
- ++i;
- }
- hPtr = Tcl_NextHashEntry(&search);
- }
- if (interp == NULL) {
- ret = (i > 0) ? TCL_OK : TCL_BREAK;
- }
- Unlock();
- return ret;
- }
- /*
- * Mount point sometimes is a relative or otherwise denormalized path.
- * But an absolute name is needed as mount point here.
- */
- Tcl_DStringInit(&dsm);
- mntpt = CanonicalPath("",mntpt, &dsm, 1);
+ WriteLock();
- if (zipname == NULL) {
- if (interp == NULL) {
- Unlock();
- return TCL_OK;
- }
-
- Tcl_DStringInit(&ds);
-
- hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, mntpt);
- if (hPtr != NULL) {
- if ((zf = Tcl_GetHashValue(hPtr)) != NULL) {
- Tcl_SetObjResult(interp,Tcl_NewStringObj(zf->name, -1));
- }
- }
- Unlock();
- return TCL_OK;
- }
- Unlock();
pwlen = 0;
if (passwd != NULL) {
pwlen = strlen(passwd);
@@ -1272,17 +1222,17 @@ TclZipfs_Mount(
return TCL_ERROR;
}
}
- if (ZipFSOpenArchive(interp, zipname, 1, &zf0) != TCL_OK) {
- return TCL_ERROR;
- }
+ /*
+ * Mount point sometimes is a relative or otherwise denormalized path.
+ * But an absolute name is needed as mount point here.
+ */
Tcl_DStringInit(&ds);
-#if HAS_DRIVES
- realname = AbsolutePath(zipname, NULL, &ds);
-#else
- realname = AbsolutePath(zipname, &ds);
-#endif
-
- WriteLock();
+ Tcl_DStringInit(&dsm);
+ if (strcmp(mntpt, "/") == 0) {
+ mntpt = "";
+ } else {
+ mntpt = CanonicalPath("",mntpt, &dsm, 1);
+ }
hPtr = Tcl_CreateHashEntry(&ZipFS.zipHash, mntpt, &isNew);
if (!isNew) {
zf = (ZipFile *) Tcl_GetHashValue(hPtr);
@@ -1290,30 +1240,29 @@ TclZipfs_Mount(
Tcl_AppendResult(interp, zf->name, " is already mounted on ", mntpt, (char *) NULL);
}
Unlock();
- ZipFSCloseArchive(interp, &zf0);
+ ZipFSCloseArchive(interp, zf0);
return TCL_ERROR;
}
- if (strcmp(mntpt, "/") == 0) {
- mntpt = "";
- }
zf = (ZipFile *) Tcl_AttemptAlloc(sizeof (*zf) + strlen(mntpt) + 1);
if (zf == NULL) {
if (interp != NULL) {
Tcl_AppendResult(interp, "out of memory", (char *) NULL);
}
Unlock();
- ZipFSCloseArchive(interp, &zf0);
+ ZipFSCloseArchive(interp, zf0);
return TCL_ERROR;
- }
- *zf = zf0;
- zf->mntpt = Tcl_GetHashKey(&ZipFS.zipHash, hPtr);
- zf->mntptlen=strlen(zf->mntpt);
- zf->name = strdup(zipname);
- zf->entries = NULL;
- zf->topents = NULL;
- zf->nopen = 0;
- Tcl_SetHashValue(hPtr, (ClientData) zf);
- if ((zf->pwbuf[0] == 0) && pwlen) {
+ }
+ Unlock();
+ *zf = *zf0;
+ zf->mntpt = Tcl_GetHashKey(&ZipFS.zipHash, hPtr);
+ zf->mntptlen=strlen(zf->mntpt);
+ zf->name = strdup(zipname);
+ zf->namelen= strlen(zipname);
+ zf->entries = NULL;
+ zf->topents = NULL;
+ zf->nopen = 0;
+ Tcl_SetHashValue(hPtr, (ClientData) zf);
+ if ((zf->pwbuf[0] == 0) && pwlen) {
int k = 0;
i = pwlen;
zf->pwbuf[k++] = i;
@@ -1352,7 +1301,6 @@ TclZipfs_Mount(
}
q = zf->data + zf->centoffs;
Tcl_DStringInit(&fpBuf);
- Tcl_DStringInit(&ds);
for (i = 0; i < zf->nfiles; i++) {
int pathlen, comlen, extra, isdir = 0, dosTime, dosDate, nbcompr, offs;
unsigned char *lq, *gq = NULL;
@@ -1514,12 +1462,229 @@ TclZipfs_Mount(
nextent:
q += pathlen + comlen + extra + ZIP_CENTRAL_HEADER_LEN;
}
- Unlock();
Tcl_DStringFree(&fpBuf);
Tcl_DStringFree(&ds);
Tcl_FSMountsChanged(NULL);
+ Unlock();
return TCL_OK;
}
+
+static void TclZipfs_C_Init(void) {
+ static const Tcl_Time t = { 0, 0 };
+ if (!ZipFS.initialized) {
+#ifdef TCL_THREADS
+ /*
+ * Inflate condition variable.
+ */
+ Tcl_MutexLock(&ZipFSMutex);
+ Tcl_ConditionWait(&ZipFSCond, &ZipFSMutex, &t);
+ Tcl_MutexUnlock(&ZipFSMutex);
+#endif
+ Tcl_FSRegister(NULL, &zipfsFilesystem);
+ Tcl_InitHashTable(&ZipFS.fileHash, TCL_STRING_KEYS);
+ Tcl_InitHashTable(&ZipFS.zipHash, TCL_STRING_KEYS);
+ ZipFS.initialized = ZipFS.idCount = 1;
+ }
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * TclZipfs_Mount --
+ *
+ * This procedure is invoked to mount a given ZIP archive file on
+ * a given mountpoint with optional ZIP password.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * A ZIP archive file is read, analyzed and mounted, resources are
+ * allocated.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+int
+TclZipfs_Mount(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ const char *zipname,
+ const char *passwd
+) {
+ int i, pwlen;
+ ZipFile *zf;
+
+ ReadLock();
+ if (!ZipFS.initialized) {
+ TclZipfs_C_Init();
+ }
+ if (mntpt == NULL) {
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int ret = TCL_OK;
+ i = 0;
+ hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search);
+ while (hPtr != NULL) {
+ if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) {
+ if (interp != NULL) {
+ Tcl_AppendElement(interp, zf->mntpt);
+ Tcl_AppendElement(interp, zf->name);
+ }
+ ++i;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (interp == NULL) {
+ ret = (i > 0) ? TCL_OK : TCL_BREAK;
+ }
+ Unlock();
+ return ret;
+ }
+
+ if (zipname == NULL) {
+ Tcl_HashEntry *hPtr;
+ if (interp == NULL) {
+ Unlock();
+ return TCL_OK;
+ }
+ hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, mntpt);
+ if (hPtr != NULL) {
+ if ((zf = Tcl_GetHashValue(hPtr)) != NULL) {
+ Tcl_SetObjResult(interp,Tcl_NewStringObj(zf->name, -1));
+ }
+ }
+ Unlock();
+ return TCL_OK;
+ }
+ Unlock();
+ pwlen = 0;
+ if (passwd != NULL) {
+ pwlen = strlen(passwd);
+ if ((pwlen > 255) || (strchr(passwd, 0xff) != NULL)) {
+ if (interp) {
+ Tcl_SetObjResult(interp,
+ Tcl_NewStringObj("illegal password", -1));
+ }
+ return TCL_ERROR;
+ }
+ }
+ zf = (ZipFile *) Tcl_AttemptAlloc(sizeof (*zf) + strlen(mntpt) + 1);
+ if (zf == NULL) {
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "out of memory", (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
+ if (ZipFSOpenArchive(interp, zipname, 1, zf) != TCL_OK) {
+ return TCL_ERROR;
+ }
+ return ZipFS_Catalogue_Filesystem(interp,zf,mntpt,passwd,zipname);
+}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * TclZipfs_Mount_Buffer --
+ *
+ * This procedure is invoked to mount a given ZIP archive file on
+ * a given mountpoint with optional ZIP password.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * A ZIP archive file is read, analyzed and mounted, resources are
+ * allocated.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+int
+TclZipfs_Mount_Buffer(
+ Tcl_Interp *interp,
+ const char *mntpt,
+ unsigned char *data,
+ size_t datalen,
+ int copy
+) {
+ int i;
+ ZipFile *zf;
+
+ ReadLock();
+ if (!ZipFS.initialized) {
+ TclZipfs_C_Init();
+ }
+ if (mntpt == NULL) {
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int ret = TCL_OK;
+
+ i = 0;
+ hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search);
+ while (hPtr != NULL) {
+ if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) {
+ if (interp != NULL) {
+ Tcl_AppendElement(interp, zf->mntpt);
+ Tcl_AppendElement(interp, zf->name);
+ }
+ ++i;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (interp == NULL) {
+ ret = (i > 0) ? TCL_OK : TCL_BREAK;
+ }
+ Unlock();
+ return ret;
+ }
+
+ if (data == NULL) {
+ Tcl_HashEntry *hPtr;
+
+ if (interp == NULL) {
+ Unlock();
+ return TCL_OK;
+ }
+ hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, mntpt);
+ if (hPtr != NULL) {
+ if ((zf = Tcl_GetHashValue(hPtr)) != NULL) {
+ Tcl_SetObjResult(interp,Tcl_NewStringObj(zf->name, -1));
+ }
+ }
+ Unlock();
+ return TCL_OK;
+ }
+ Unlock();
+ zf = (ZipFile *) Tcl_AttemptAlloc(sizeof (*zf) + strlen(mntpt) + 1);
+ if (zf == NULL) {
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "out of memory", (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
+ zf->is_membuf=1;
+ zf->length=datalen;
+ if(copy) {
+ zf->data=(unsigned char *)Tcl_AttemptAlloc(datalen);
+ if (zf->data == NULL) {
+ if (interp != NULL) {
+ Tcl_AppendResult(interp, "out of memory", (char *) NULL);
+ }
+ return TCL_ERROR;
+ }
+ memcpy(zf->data,data,datalen);
+ zf->tofree=zf->data;
+ } else {
+ zf->data=data;
+ zf->tofree=NULL;
+ }
+ if(ZipFS_Find_TOC(interp,0,zf)!=TCL_OK) {
+ return TCL_ERROR;
+ }
+ return ZipFS_Catalogue_Filesystem(interp,zf,mntpt,NULL,"Memory Buffer");
+}
/*
*-------------------------------------------------------------------------
@@ -1579,7 +1744,6 @@ TclZipfs_Unmount(Tcl_Interp *interp, const char *mntpt)
Tcl_Free((char *) z);
}
ZipFSCloseArchive(interp, zf);
- free(zf->name); //Allocated by strdup
Tcl_Free((char *) zf);
unmounted = 1;
done:
@@ -1612,13 +1776,88 @@ ZipFSMountObjCmd(
) {
if (objc > 4) {
Tcl_WrongNumArgs(interp, 1, objv,
- "?zipfile? ?mountpoint? ?password?");
+ "?mountpoint? ?zipfile? ?password?");
return TCL_ERROR;
}
return TclZipfs_Mount(interp, (objc > 1) ? Tcl_GetString(objv[1]) : NULL,
(objc > 2) ? Tcl_GetString(objv[2]) : NULL,
(objc > 3) ? Tcl_GetString(objv[3]) : NULL);
}
+
+/*
+ *-------------------------------------------------------------------------
+ *
+ * ZipFSMountObjCmd --
+ *
+ * This procedure is invoked to process the "zipfs::mount" command.
+ *
+ * Results:
+ * A standard Tcl result.
+ *
+ * Side effects:
+ * A ZIP archive file is mounted, resources are allocated.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+static int
+ZipFSMountBufferObjCmd(
+ ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]
+) {
+ const char *mntpt;
+ unsigned char *data;
+ int length;
+ if (objc > 4) {
+ Tcl_WrongNumArgs(interp, 1, objv, "?mountpoint? ?data?");
+ return TCL_ERROR;
+ }
+ if(objc<2) {
+ int i;
+ Tcl_HashEntry *hPtr;
+ Tcl_HashSearch search;
+ int ret = TCL_OK;
+ ZipFile *zf;
+
+ ReadLock();
+ i = 0;
+ hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search);
+ while (hPtr != NULL) {
+ if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) {
+ if (interp != NULL) {
+ Tcl_AppendElement(interp, zf->mntpt);
+ Tcl_AppendElement(interp, zf->name);
+ }
+ ++i;
+ }
+ hPtr = Tcl_NextHashEntry(&search);
+ }
+ if (interp == NULL) {
+ ret = (i > 0) ? TCL_OK : TCL_BREAK;
+ }
+ Unlock();
+ return ret;
+ }
+ mntpt=Tcl_GetString(objv[1]);
+ if(objc<3) {
+ Tcl_HashEntry *hPtr;
+ ZipFile *zf;
+
+ if (interp == NULL) {
+ Unlock();
+ return TCL_OK;
+ }
+ hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, mntpt);
+ if (hPtr != NULL) {
+ if ((zf = Tcl_GetHashValue(hPtr)) != NULL) {
+ Tcl_SetObjResult(interp,Tcl_NewStringObj(zf->name, -1));
+ }
+ }
+ Unlock();
+ return TCL_OK;
+ }
+ data=Tcl_GetByteArrayFromObj(objv[2],&length);
+ return TclZipfs_Mount_Buffer(interp, mntpt,data,length,1);
+}
/*
*-------------------------------------------------------------------------
@@ -2477,11 +2716,10 @@ ZipFSLMkImgObjCmd(ClientData clientData, Tcl_Interp *interp,
/*
*-------------------------------------------------------------------------
*
- * ZipFSExistsObjCmd --
+ * ZipFSCanonicalObjCmd --
*
- * This procedure is invoked to process the "zipfs::exists" command.
- * It tests for the existence of a file in the ZIP filesystem and
- * places a boolean into the interp's result.
+ * This procedure is invoked to process the "zipfs::canonical" command.
+ * It returns the canonical name for a file within zipfs
*
* Results:
* Always TCL_OK.
@@ -4137,6 +4375,7 @@ TclZipfs_Init(Tcl_Interp *interp)
if(interp != NULL) {
static const EnsembleImplMap initMap[] = {
{"mount", ZipFSMountObjCmd, NULL, NULL, NULL, 0},
+ {"mount_data", ZipFSMountBufferObjCmd, NULL, NULL, NULL, 0},
{"unmount", ZipFSUnmountObjCmd, NULL, NULL, NULL, 0},
{"mkkey", ZipFSMkKeyObjCmd, NULL, NULL, NULL, 0},
{"mkimg", ZipFSMkImgObjCmd, NULL, NULL, NULL, 0},
diff --git a/tests/zipfs.test b/tests/zipfs.test
index 060e4a6..5f5b93c 100644
--- a/tests/zipfs.test
+++ b/tests/zipfs.test
@@ -105,7 +105,7 @@ test zipfs-0.12 {zipfs basics: join} -constraints zipfs -body {
test zipfs-1.3 {zipfs errors} -constraints zipfs -returnCodes error -body {
zipfs mount a b c d e f
-} -result {wrong # args: should be "zipfs mount ?zipfile? ?mountpoint? ?password?"}
+} -result {wrong # args: should be "zipfs mount ?mountpoint? ?zipfile? ?password?"}
test zipfs-1.4 {zipfs errors} -constraints zipfs -returnCodes error -body {
zipfs unmount a b c d e f
@@ -159,11 +159,8 @@ test zipfs-2.2.0 {zipfs mkzip} -constraints zipfs -body {
cd $CWD
} -result "[zipfs root]abc/cp850.enc"
-skip [concat [skip] zipfs-2.2.*]
-
-
if {![zipfs exists /abc/cp850.enc]} {
- tcltest::skip zipfs-2.2.*
+ skip [concat [skip] zipfs-2.2.*]
}
test zipfs-2.2.1 {zipfs info} -constraints zipfs -body {
@@ -210,7 +207,73 @@ test zipfs-2.2.6 {zipfs unmount} -constraints zipfs -body {
zipfs exists /abc/cp850.enc
} -result 0
+
+###
+# Repeat the tests for a buffer mounted archive
+###
+test zipfs-2.3.0 {zipfs mkzip} -constraints zipfs -body {
+ cd $tcl_library/encoding
+ zipfs mkzip $zipfile .
+ set fin [open $zipfile r]
+ fconfigure $fin -translation binary
+ set dat [read $fin]
+ close $fin
+ zipfs mount_data def $dat
+ zipfs list -glob ${ziproot}def/cp850.*
+} -cleanup {
+ cd $CWD
+} -result "[zipfs root]def/cp850.enc"
+
+if {![zipfs exists /def/cp850.enc]} {
+ skip [concat [skip] zipfs-2.3.*]
+}
+
+test zipfs-2.3.1 {zipfs info} -constraints zipfs -body {
+ set r [zipfs info ${ziproot}def/cp850.enc]
+ lrange $r 0 2
+} -result [list {Memory Buffer} 1090 527] ;# NOTE: Only the first 3 results are stable
+
+test zipfs-2.3.3 {zipfs data} -constraints zipfs -body {
+ set zipfd [open ${ziproot}/def/cp850.enc] ;# FIXME: leave open - see later test
+ read $zipfd
+} -result {# Encoding file: cp850, single-byte
+S
+003F 0 1
+00
+0000000100020003000400050006000700080009000A000B000C000D000E000F
+0010001100120013001400150016001700180019001A001B001C001D001E001F
+0020002100220023002400250026002700280029002A002B002C002D002E002F
+0030003100320033003400350036003700380039003A003B003C003D003E003F
+0040004100420043004400450046004700480049004A004B004C004D004E004F
+0050005100520053005400550056005700580059005A005B005C005D005E005F
+0060006100620063006400650066006700680069006A006B006C006D006E006F
+0070007100720073007400750076007700780079007A007B007C007D007E007F
+00C700FC00E900E200E400E000E500E700EA00EB00E800EF00EE00EC00C400C5
+00C900E600C600F400F600F200FB00F900FF00D600DC00F800A300D800D70192
+00E100ED00F300FA00F100D100AA00BA00BF00AE00AC00BD00BC00A100AB00BB
+2591259225932502252400C100C200C000A9256325512557255D00A200A52510
+25142534252C251C2500253C00E300C3255A25542569256625602550256C00A4
+00F000D000CA00CB00C8013100CD00CE00CF2518250C2588258400A600CC2580
+00D300DF00D400D200F500D500B500FE00DE00DA00DB00D900FD00DD00AF00B4
+00AD00B1201700BE00B600A700F700B800B000A800B700B900B300B225A000A0
+} ;# FIXME: result depends on content of encodings dir
+
+test zipfs-2.3.4 {zipfs exists} -constraints zipfs -body {
+ zipfs exists /def/cp850.enc
+} -result 1
+
+test zipfs-2.3.5 {zipfs unmount while busy} -constraints zipfs -body {
+ zipfs unmount /def
+} -returnCodes error -result {filesystem is busy}
+
+test zipfs-2.3.6 {zipfs unmount} -constraints zipfs -body {
+ close $zipfd
+ zipfs unmount /def
+ zipfs exists /def/cp850.enc
+} -result 0
+
catch {file delete -force $tmpdir}
+
::tcltest::cleanupTests
return