From 608373fcb170fe76512b46c7ce07cc0691720ae5 Mon Sep 17 00:00:00 2001 From: hypnotoad Date: Wed, 17 Jan 2018 15:56:32 +0000 Subject: Modifications to allow the mounting of zip file systems from data blocks Added a new stubs entry to mount a data block as a zip file system --- generic/tcl.decls | 15 +- generic/tclDecls.h | 14 +- generic/tclStubInit.c | 1 + generic/tclZipfs.c | 493 +++++++++++++++++++++++++++++++++++++------------- tests/zipfs.test | 73 +++++++- 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 -- cgit v0.12