Index: generic/tcl.decls ================================================================== --- generic/tcl.decls +++ generic/tcl.decls @@ -940,14 +940,14 @@ int Tcl_DumpActiveMemory(const char *fileName) } declare 266 { void Tcl_ValidateAllMemory(const char *file, int line) } -declare 267 { +declare 267 {deprecated {see TIP #422}} { void Tcl_AppendResultVA(Tcl_Interp *interp, va_list argList) } -declare 268 { +declare 268 {deprecated {see TIP #422}} { void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, va_list argList) } declare 269 { char *Tcl_HashStats(Tcl_HashTable *tablePtr) } @@ -971,20 +971,20 @@ # TIP #268: The internally used new Require function is in slot 573. declare 274 { CONST84_RETURN char *Tcl_PkgRequire(Tcl_Interp *interp, const char *name, const char *version, int exact) } -declare 275 { +declare 275 {deprecated {see TIP #422}} { void Tcl_SetErrorCodeVA(Tcl_Interp *interp, va_list argList) } -declare 276 { +declare 276 {deprecated {see TIP #422}} { int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList) } declare 277 { Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options) } -declare 278 { +declare 278 {deprecated {see TIP #422}} { TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList) } declare 279 { void Tcl_GetVersion(int *major, int *minor, int *patchLevel, int *type) } Index: generic/tclDecls.h ================================================================== --- generic/tclDecls.h +++ generic/tclDecls.h @@ -812,14 +812,16 @@ /* 265 */ EXTERN int Tcl_DumpActiveMemory(const char *fileName); /* 266 */ EXTERN void Tcl_ValidateAllMemory(const char *file, int line); /* 267 */ -EXTERN void Tcl_AppendResultVA(Tcl_Interp *interp, +TCL_DEPRECATED("see TIP #422") +void Tcl_AppendResultVA(Tcl_Interp *interp, va_list argList); /* 268 */ -EXTERN void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, +TCL_DEPRECATED("see TIP #422") +void Tcl_AppendStringsToObjVA(Tcl_Obj *objPtr, va_list argList); /* 269 */ EXTERN char * Tcl_HashStats(Tcl_HashTable *tablePtr); /* 270 */ EXTERN CONST84_RETURN char * Tcl_ParseVar(Tcl_Interp *interp, @@ -838,18 +840,21 @@ /* 274 */ EXTERN CONST84_RETURN char * Tcl_PkgRequire(Tcl_Interp *interp, const char *name, const char *version, int exact); /* 275 */ -EXTERN void Tcl_SetErrorCodeVA(Tcl_Interp *interp, +TCL_DEPRECATED("see TIP #422") +void Tcl_SetErrorCodeVA(Tcl_Interp *interp, va_list argList); /* 276 */ -EXTERN int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList); +TCL_DEPRECATED("see TIP #422") +int Tcl_VarEvalVA(Tcl_Interp *interp, va_list argList); /* 277 */ EXTERN Tcl_Pid Tcl_WaitPid(Tcl_Pid pid, int *statPtr, int options); /* 278 */ -EXTERN TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList); +TCL_DEPRECATED("see TIP #422") +TCL_NORETURN void Tcl_PanicVA(const char *format, va_list argList); /* 279 */ EXTERN void Tcl_GetVersion(int *major, int *minor, int *patchLevel, int *type); /* 280 */ EXTERN void Tcl_InitMemory(Tcl_Interp *interp); @@ -2142,22 +2147,22 @@ ClientData (*tcl_VarTraceInfo2) (Tcl_Interp *interp, const char *part1, const char *part2, int flags, Tcl_VarTraceProc *procPtr, ClientData prevClientData); /* 262 */ int (*tcl_Write) (Tcl_Channel chan, const char *s, int slen); /* 263 */ void (*tcl_WrongNumArgs) (Tcl_Interp *interp, int objc, Tcl_Obj *const objv[], const char *message); /* 264 */ int (*tcl_DumpActiveMemory) (const char *fileName); /* 265 */ void (*tcl_ValidateAllMemory) (const char *file, int line); /* 266 */ - void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */ - void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendResultVA) (Tcl_Interp *interp, va_list argList); /* 267 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_AppendStringsToObjVA) (Tcl_Obj *objPtr, va_list argList); /* 268 */ char * (*tcl_HashStats) (Tcl_HashTable *tablePtr); /* 269 */ CONST84_RETURN char * (*tcl_ParseVar) (Tcl_Interp *interp, const char *start, CONST84 char **termPtr); /* 270 */ CONST84_RETURN char * (*tcl_PkgPresent) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 271 */ CONST84_RETURN char * (*tcl_PkgPresentEx) (Tcl_Interp *interp, const char *name, const char *version, int exact, void *clientDataPtr); /* 272 */ int (*tcl_PkgProvide) (Tcl_Interp *interp, const char *name, const char *version); /* 273 */ CONST84_RETURN char * (*tcl_PkgRequire) (Tcl_Interp *interp, const char *name, const char *version, int exact); /* 274 */ - void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */ - int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */ + TCL_DEPRECATED_API("see TIP #422") void (*tcl_SetErrorCodeVA) (Tcl_Interp *interp, va_list argList); /* 275 */ + TCL_DEPRECATED_API("see TIP #422") int (*tcl_VarEvalVA) (Tcl_Interp *interp, va_list argList); /* 276 */ Tcl_Pid (*tcl_WaitPid) (Tcl_Pid pid, int *statPtr, int options); /* 277 */ - TCL_NORETURN1 void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */ + TCL_DEPRECATED_API("see TIP #422") TCL_NORETURN1 void (*tcl_PanicVA) (const char *format, va_list argList); /* 278 */ void (*tcl_GetVersion) (int *major, int *minor, int *patchLevel, int *type); /* 279 */ void (*tcl_InitMemory) (Tcl_Interp *interp); /* 280 */ Tcl_Channel (*tcl_StackChannel) (Tcl_Interp *interp, const Tcl_ChannelType *typePtr, ClientData instanceData, int mask, Tcl_Channel prevChan); /* 281 */ int (*tcl_UnstackChannel) (Tcl_Interp *interp, Tcl_Channel chan); /* 282 */ Tcl_Channel (*tcl_GetStackedChannel) (Tcl_Channel chan); /* 283 */ Index: generic/tclFileName.c ================================================================== --- generic/tclFileName.c +++ generic/tclFileName.c @@ -1879,11 +1879,11 @@ */ separators = "/\\"; } else if (tclPlatform == TCL_PLATFORM_UNIX) { - if (pathPrefix == NULL && tail[0] == '/') { + if (pathPrefix == NULL && tail[0] == '/' && tail[1] != '/') { pathPrefix = Tcl_NewStringObj(tail, 1); tail++; Tcl_IncrRefCount(pathPrefix); } } Index: generic/tclStubInit.c ================================================================== --- generic/tclStubInit.c +++ generic/tclStubInit.c @@ -70,10 +70,15 @@ # define TclWinSetSockOpt 0 # define TclWinNToHS 0 # define TclBNInitBignumFromWideUInt 0 # define TclBNInitBignumFromWideInt 0 # define TclBNInitBignumFromLong 0 +# define Tcl_AppendResultVA 0 +# define Tcl_AppendStringsToObjVA 0 +# define Tcl_SetErrorCodeVA 0 +# define Tcl_PanicVA 0 +# define Tcl_VarEvalVA 0 #else #define TclSetStartupScriptPath setStartupScriptPath static void TclSetStartupScriptPath(Tcl_Obj *path) { Tcl_SetStartupScript(path, NULL); Index: generic/tclZipfs.c ================================================================== --- generic/tclZipfs.c +++ generic/tclZipfs.c @@ -26,15 +26,15 @@ #ifdef HAVE_ZLIB #include "zlib.h" #include "crypt.h" -#define ZIPFS_VOLUME "zipfs:/" -#define ZIPFS_APP_MOUNT "zipfs:/app" -#define ZIPFS_ZIP_MOUNT "zipfs:/lib/tcl" +#define ZIPFS_VOLUME "//zipfs:/" +#define ZIPFS_APP_MOUNT "//zipfs:/app" +#define ZIPFS_ZIP_MOUNT "//zipfs:/lib/tcl" -#define ZIPFS_VOLUME_LEN 7 +#define ZIPFS_VOLUME_LEN 9 /* * Various constants and offsets found in ZIP archive files */ @@ -501,192 +501,148 @@ */ static char * CanonicalPath(const char *root, const char *tail, Tcl_DString *dsPtr,int ZIPFSPATH) { - char *path; - char *result; - int i, j, c, isunc = 0, isvfs=0, n=0; -#if HAS_DRIVES - int zipfspath=1; - if ((tail[0] != '\0') && (strchr(drvletters, tail[0]) != NULL) && - (tail[1] == ':')) { - tail += 2; - zipfspath=0; - } - /* UNC style path */ - if (tail[0] == '\\') { - root = ""; - ++tail; - zipfspath=0; - } - if (tail[0] == '\\') { - root = "/"; - ++tail; - zipfspath=0; - } - if(zipfspath) { -#endif - /* UNC style path */ - if(root && strncmp(root,ZIPFS_VOLUME,ZIPFS_VOLUME_LEN)==0) { - isvfs=1; - } else if (tail && strncmp(tail,ZIPFS_VOLUME,ZIPFS_VOLUME_LEN) == 0) { - isvfs=2; - } - if(isvfs!=1) { - if ((root[0] == '/') && (root[1] == '/')) { - isunc = 1; - } - } -#if HAS_DRIVES - } -#endif - if(isvfs!=2) { - if (tail[0] == '/') { - if(isvfs!=1) { - root = ""; - } - ++tail; - isunc = 0; - } - if (tail[0] == '/') { - if(isvfs!=1) { - root = "/"; - } - ++tail; - isunc = 1; - } - } - i = strlen(root); - j = strlen(tail); - if(isvfs==1) { - if(i>ZIPFS_VOLUME_LEN) { - Tcl_DStringSetLength(dsPtr, i + j + 1); - path = Tcl_DStringValue(dsPtr); - memcpy(path, root, i); - path[i++] = '/'; - memcpy(path + i, tail, j); - } else { - Tcl_DStringSetLength(dsPtr, i + j); - path = Tcl_DStringValue(dsPtr); - memcpy(path, root, i); - memcpy(path + i, tail, j); - } - } else if(isvfs==2) { - Tcl_DStringSetLength(dsPtr, j); - path = Tcl_DStringValue(dsPtr); - memcpy(path, tail, j); - } else { - if (ZIPFSPATH) { - Tcl_DStringSetLength(dsPtr, i + j + ZIPFS_VOLUME_LEN); - path = Tcl_DStringValue(dsPtr); - memcpy(path, ZIPFS_VOLUME, ZIPFS_VOLUME_LEN); - memcpy(path + ZIPFS_VOLUME_LEN + i , tail, j); - } else { - Tcl_DStringSetLength(dsPtr, i + j + 1); - path = Tcl_DStringValue(dsPtr); - memcpy(path, root, i); - path[i++] = '/'; - memcpy(path + i, tail, j); - } - } -#if HAS_DRIVES - for (i = 0; path[i] != '\0'; i++) { - if (path[i] == '\\') { - path[i] = '/'; - } - } -#endif - if(ZIPFSPATH) { - n=ZIPFS_VOLUME_LEN; - } else { - n=0; - } - for (i = j = n; (c = path[i]) != '\0'; i++) { - if (c == '/') { + char *path; + char *result; + int i, j, c, isunc = 0, isvfs=0, n=0; +#if HAS_DRIVES + int zipfspath=1; + if ((tail[0] != '\0') && (strchr(drvletters, tail[0]) != NULL) && + (tail[1] == ':')) { + tail += 2; + zipfspath=0; + } + /* UNC style path */ + if (tail[0] == '\\') { + root = ""; + ++tail; + zipfspath=0; + } + if (tail[0] == '\\') { + root = "/"; + ++tail; + zipfspath=0; + } + if(zipfspath) { +#endif + /* UNC style path */ + if(root && strncmp(root,ZIPFS_VOLUME,ZIPFS_VOLUME_LEN)==0) { + isvfs=1; + } else if (tail && strncmp(tail,ZIPFS_VOLUME,ZIPFS_VOLUME_LEN) == 0) { + isvfs=2; + } + if(isvfs!=1) { + if ((root[0] == '/') && (root[1] == '/')) { + isunc = 1; + } + } +#if HAS_DRIVES + } +#endif + if(isvfs!=2) { + if (tail[0] == '/') { + if(isvfs!=1) { + root = ""; + } + ++tail; + isunc = 0; + } + if (tail[0] == '/') { + if(isvfs!=1) { + root = "/"; + } + ++tail; + isunc = 1; + } + } + i = strlen(root); + j = strlen(tail); + if(isvfs==1) { + if(i>ZIPFS_VOLUME_LEN) { + Tcl_DStringSetLength(dsPtr, i + j + 1); + path = Tcl_DStringValue(dsPtr); + memcpy(path, root, i); + path[i++] = '/'; + memcpy(path + i, tail, j); + } else { + Tcl_DStringSetLength(dsPtr, i + j); + path = Tcl_DStringValue(dsPtr); + memcpy(path, root, i); + memcpy(path + i, tail, j); + } + } else if(isvfs==2) { + Tcl_DStringSetLength(dsPtr, j); + path = Tcl_DStringValue(dsPtr); + memcpy(path, tail, j); + } else { + if (ZIPFSPATH) { + Tcl_DStringSetLength(dsPtr, i + j + ZIPFS_VOLUME_LEN); + path = Tcl_DStringValue(dsPtr); + memcpy(path, ZIPFS_VOLUME, ZIPFS_VOLUME_LEN); + memcpy(path + ZIPFS_VOLUME_LEN + i , tail, j); + } else { + Tcl_DStringSetLength(dsPtr, i + j + 1); + path = Tcl_DStringValue(dsPtr); + memcpy(path, root, i); + path[i++] = '/'; + memcpy(path + i, tail, j); + } + } +#if HAS_DRIVES + for (i = 0; path[i] != '\0'; i++) { + if (path[i] == '\\') { + path[i] = '/'; + } + } +#endif + if(ZIPFSPATH) { + n=ZIPFS_VOLUME_LEN; + } else { + n=0; + } + for (i = j = n; (c = path[i]) != '\0'; i++) { + if (c == '/') { int c2 = path[i + 1]; if (c2 == '/') { - continue; + continue; } if (c2 == '.') { - int c3 = path[i + 2]; - if ((c3 == '/') || (c3 == '\0')) { - i++; - continue; - } - if ((c3 == '.') && - ((path[i + 3] == '/') || (path [i + 3] == '\0'))) { - i += 2; - while ((j > 0) && (path[j - 1] != '/')) { - j--; - } - if (j > isunc) { - --j; - while ((j > 1 + isunc) && (path[j - 2] == '/')) { - j--; - } - } - continue; - } - } - } - path[j++] = c; - } - if (j == 0) { - path[j++] = '/'; - } - path[j] = 0; - Tcl_DStringSetLength(dsPtr, j); - result=Tcl_DStringValue(dsPtr); - return result; -} - - - -/* - *------------------------------------------------------------------------- - * - * AbsolutePath -- - * - * This function computes the absolute path from a given - * (relative) path name into the specified Tcl_DString. - * - * Results: - * Returns the pointer to the absolute path contained in the - * specified Tcl_DString. - * - * Side effects: - * Modifies the specified Tcl_DString. - * - *------------------------------------------------------------------------- - */ - -static char * -AbsolutePath(const char *path, - Tcl_DString *dsPtr, - int ZIPFSPATH) -{ - char *result; - if (*path == '~') { - Tcl_DStringAppend(dsPtr, path, -1); - return Tcl_DStringValue(dsPtr); - } - if (*path != '/') { - Tcl_DString pwd; - - /* relative path */ - Tcl_DStringInit(&pwd); - Tcl_GetCwd(NULL, &pwd); - result = Tcl_DStringValue(&pwd); - result = CanonicalPath(result, path, dsPtr,ZIPFSPATH); - Tcl_DStringFree(&pwd); - } else { - /* absolute path */ - result = CanonicalPath("", path, dsPtr,ZIPFSPATH); - } - return result; -} + int c3 = path[i + 2]; + if ((c3 == '/') || (c3 == '\0')) { + i++; + continue; + } + if ((c3 == '.') && + ((path[i + 3] == '/') || (path [i + 3] == '\0'))) { + i += 2; + while ((j > 0) && (path[j - 1] != '/')) { + j--; + } + if (j > isunc) { + --j; + while ((j > 1 + isunc) && (path[j - 2] == '/')) { + j--; + } + } + continue; + } + } + } + path[j++] = c; + } + if (j == 0) { + path[j++] = '/'; + } + path[j] = 0; + Tcl_DStringSetLength(dsPtr, j); + result=Tcl_DStringValue(dsPtr); + return result; +} + + /* *------------------------------------------------------------------------- * * ZipFSLookup -- @@ -706,21 +662,18 @@ */ static ZipEntry * ZipFSLookup(char *filename) { - char *realname; - - Tcl_HashEntry *hPtr; - ZipEntry *z; - Tcl_DString ds; - Tcl_DStringInit(&ds); - realname = AbsolutePath(filename, &ds, 1); - hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, realname); - z = hPtr ? (ZipEntry *) Tcl_GetHashValue(hPtr) : NULL; - Tcl_DStringFree(&ds); - return z; + Tcl_HashEntry *hPtr; + ZipEntry *z; + Tcl_DString ds; + Tcl_DStringInit(&ds); + hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, filename); + z = hPtr ? (ZipEntry *) Tcl_GetHashValue(hPtr) : NULL; + Tcl_DStringFree(&ds); + return z; } #ifdef NEVER_USED /* @@ -741,30 +694,25 @@ */ static int ZipFSLookupMount(char *filename) { - char *realname; - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - ZipFile *zf; - Tcl_DString ds; - int match = 0; - Tcl_DStringInit(&ds); - realname = AbsolutePath(filename, &ds, 1); - hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); - while (hPtr != NULL) { - if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) { - if (strcmp(zf->mntpt, realname) == 0) { - match = 1; - break; - } - } - hPtr = Tcl_NextHashEntry(&search); - } - Tcl_DStringFree(&ds); - return match; + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + ZipFile *zf; + int match = 0; + hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); + while (hPtr != NULL) { + if ((zf = (ZipFile *) Tcl_GetHashValue(hPtr)) != NULL) { + if (strcmp(zf->mntpt, filename) == 0) { + match = 1; + break; + } + } + hPtr = Tcl_NextHashEntry(&search); + } + return match; } #endif /* *------------------------------------------------------------------------- @@ -1050,206 +998,194 @@ int TclZipfs_Mount(Tcl_Interp *interp, const char *zipname, const char *mntpt, const char *passwd) { - char *realname, *p; - int i, pwlen, isNew; - ZipFile *zf, zf0; - ZipEntry *z; - Tcl_HashEntry *hPtr; - Tcl_DString ds, dsm, fpBuf; - unsigned char *q; - - ReadLock(); - if (!ZipFS.initialized) { - if (interp != NULL) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj("not initialized", -1)); - } - Unlock(); - return TCL_ERROR; - } - if (zipname == 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; - } - if (mntpt == NULL) { - if (interp == NULL) { - Unlock(); - return TCL_OK; - } - Tcl_DStringInit(&ds); - p = AbsolutePath(zipname, &ds, 0); - hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, p); - if (hPtr != NULL) { - if ((zf = Tcl_GetHashValue(hPtr)) != NULL) { - Tcl_SetObjResult(interp, - Tcl_NewStringObj(zf->mntpt, zf->mntptlen)); - } - } - Unlock(); - Tcl_DStringFree(&ds); - 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; - } - } - if (ZipFSOpenArchive(interp, zipname, 1, &zf0) != TCL_OK) { - return TCL_ERROR; - } - Tcl_DStringInit(&ds); - realname = AbsolutePath(zipname, &ds, 0); - /* - * Mount point can come from Tcl_GetNameOfExecutable() - * which 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(); - hPtr = Tcl_CreateHashEntry(&ZipFS.zipHash, realname, &isNew); - Tcl_DStringSetLength(&ds, 0); - if (!isNew) { - zf = (ZipFile *) Tcl_GetHashValue(hPtr); - if (interp != NULL) { - Tcl_AppendResult(interp, "already mounted on \"", zf->mntptlen ? - zf->mntpt : "/", "\"", (char *) NULL); - } - Unlock(); - Tcl_DStringFree(&ds); - Tcl_DStringFree(&dsm); - 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(); - Tcl_DStringFree(&ds); - Tcl_DStringFree(&dsm); - ZipFSCloseArchive(interp, &zf0); - return TCL_ERROR; - } - *zf = zf0; - zf->name = Tcl_GetHashKey(&ZipFS.zipHash, hPtr); - strcpy(zf->mntpt, mntpt); - zf->mntptlen = strlen(zf->mntpt); - 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; - while (i > 0) { - zf->pwbuf[k] = (passwd[i - 1] & 0x0f) | - pwrot[(passwd[i - 1] >> 4) & 0x0f]; - k++; - i--; - } - zf->pwbuf[k] = '\0'; - } - if (mntpt[0] != '\0') { - z = (ZipEntry *) Tcl_Alloc(sizeof (*z)); - z->name = NULL; - z->tnext = NULL; - z->depth = CountSlashes(mntpt); - z->zipfile = zf; - z->isdir = 1; - z->isenc = 0; - z->offset = zf->baseoffs; - z->crc32 = 0; - z->timestamp = 0; - z->nbyte = z->nbytecompr = 0; - z->cmeth = ZIP_COMPMETH_STORED; - z->data = NULL; - hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, mntpt, &isNew); - if (!isNew) { - /* skip it */ - Tcl_Free((char *) z); - } else { + int i, pwlen, isNew; + ZipFile *zf, zf0; + ZipEntry *z; + Tcl_HashEntry *hPtr; + Tcl_DString ds, fpBuf; + unsigned char *q; + + ReadLock(); + if (!ZipFS.initialized) { + if (interp != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj("not initialized", -1)); + } + Unlock(); + return TCL_ERROR; + } + if (zipname == 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; + } + if (mntpt == NULL) { + if (interp == NULL) { + Unlock(); + return TCL_OK; + } + hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, zipname); + if (hPtr != NULL) { + if ((zf = Tcl_GetHashValue(hPtr)) != NULL) { + Tcl_SetObjResult(interp, + Tcl_NewStringObj(zf->mntpt, zf->mntptlen)); + } + } + 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; + } + } + if (ZipFSOpenArchive(interp, zipname, 1, &zf0) != TCL_OK) { + return TCL_ERROR; + } + /* + * Mount point can come from Tcl_GetNameOfExecutable() + * which sometimes is a relative or otherwise denormalized path. + * But an absolute name is needed as mount point here. + */ + WriteLock(); + hPtr = Tcl_CreateHashEntry(&ZipFS.zipHash, zipname, &isNew); + if (!isNew) { + zf = (ZipFile *) Tcl_GetHashValue(hPtr); + if (interp != NULL) { + Tcl_AppendResult(interp, "already mounted on \"", zf->mntptlen ? + zf->mntpt : "/", "\"", (char *) NULL); + } + Unlock(); + 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); + return TCL_ERROR; + } + *zf = zf0; + zf->name = Tcl_GetHashKey(&ZipFS.zipHash, hPtr); + strcpy(zf->mntpt, mntpt); + zf->mntptlen = strlen(zf->mntpt); + 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; + while (i > 0) { + zf->pwbuf[k] = (passwd[i - 1] & 0x0f) | + pwrot[(passwd[i - 1] >> 4) & 0x0f]; + k++; + i--; + } + zf->pwbuf[k] = '\0'; + } + if (mntpt[0] != '\0') { + z = (ZipEntry *) Tcl_Alloc(sizeof (*z)); + z->name = NULL; + z->tnext = NULL; + z->depth = CountSlashes(mntpt); + z->zipfile = zf; + z->isdir = 1; + z->isenc = 0; + z->offset = zf->baseoffs; + z->crc32 = 0; + z->timestamp = 0; + z->nbyte = z->nbytecompr = 0; + z->cmeth = ZIP_COMPMETH_STORED; + z->data = NULL; + hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, mntpt, &isNew); + if (!isNew) { + /* skip it */ + Tcl_Free((char *) z); + } else { Tcl_SetHashValue(hPtr, (ClientData) z); z->name = Tcl_GetHashKey(&ZipFS.fileHash, hPtr); z->next = zf->entries; zf->entries = z; - } - } - q = zf->data + zf->centoffs; - Tcl_DStringInit(&fpBuf); - for (i = 0; i < zf->nfiles; i++) { - int pathlen, comlen, extra, isdir = 0, dosTime, dosDate, nbcompr, offs; - unsigned char *lq, *gq = NULL; - char *fullpath, *path; - - pathlen = zip_read_short(q + ZIP_CENTRAL_PATHLEN_OFFS); - comlen = zip_read_short(q + ZIP_CENTRAL_FCOMMENTLEN_OFFS); - extra = zip_read_short(q + ZIP_CENTRAL_EXTRALEN_OFFS); - Tcl_DStringSetLength(&ds, 0); - Tcl_DStringAppend(&ds, (char *) q + ZIP_CENTRAL_HEADER_LEN, pathlen); - path = Tcl_DStringValue(&ds); - if ((pathlen > 0) && (path[pathlen - 1] == '/')) { + } + } + 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; + char *fullpath, *path; + + pathlen = zip_read_short(q + ZIP_CENTRAL_PATHLEN_OFFS); + comlen = zip_read_short(q + ZIP_CENTRAL_FCOMMENTLEN_OFFS); + extra = zip_read_short(q + ZIP_CENTRAL_EXTRALEN_OFFS); + Tcl_DStringSetLength(&ds, 0); + Tcl_DStringAppend(&ds, (char *) q + ZIP_CENTRAL_HEADER_LEN, pathlen); + path = Tcl_DStringValue(&ds); + if ((pathlen > 0) && (path[pathlen - 1] == '/')) { Tcl_DStringSetLength(&ds, pathlen - 1); path = Tcl_DStringValue(&ds); isdir = 1; - } - if ((strcmp(path, ".") == 0) || (strcmp(path, "..") == 0)) { - goto nextent; - } - lq = zf->data + zf->baseoffs + - zip_read_int(q + ZIP_CENTRAL_LOCALHDR_OFFS); - if ((lq < zf->data) || (lq > (zf->data + zf->length))) { - goto nextent; - } - nbcompr = zip_read_int(lq + ZIP_LOCAL_COMPLEN_OFFS); - if (!isdir && (nbcompr == 0) && - (zip_read_int(lq + ZIP_LOCAL_UNCOMPLEN_OFFS) == 0) && - (zip_read_int(lq + ZIP_LOCAL_CRC32_OFFS) == 0)) { + } + if ((strcmp(path, ".") == 0) || (strcmp(path, "..") == 0)) { + goto nextent; + } + lq = zf->data + zf->baseoffs + + zip_read_int(q + ZIP_CENTRAL_LOCALHDR_OFFS); + if ((lq < zf->data) || (lq > (zf->data + zf->length))) { + goto nextent; + } + nbcompr = zip_read_int(lq + ZIP_LOCAL_COMPLEN_OFFS); + if (!isdir && (nbcompr == 0) && + (zip_read_int(lq + ZIP_LOCAL_UNCOMPLEN_OFFS) == 0) && + (zip_read_int(lq + ZIP_LOCAL_CRC32_OFFS) == 0)) { gq = q; nbcompr = zip_read_int(gq + ZIP_CENTRAL_COMPLEN_OFFS); - } - offs = (lq - zf->data) - + ZIP_LOCAL_HEADER_LEN - + zip_read_short(lq + ZIP_LOCAL_PATHLEN_OFFS) - + zip_read_short(lq + ZIP_LOCAL_EXTRALEN_OFFS); - if ((offs + nbcompr) > zf->length) { + } + offs = (lq - zf->data) + + ZIP_LOCAL_HEADER_LEN + + zip_read_short(lq + ZIP_LOCAL_PATHLEN_OFFS) + + zip_read_short(lq + ZIP_LOCAL_EXTRALEN_OFFS); + if ((offs + nbcompr) > zf->length) { goto nextent; - } - if (!isdir && (mntpt[0] == '\0') && !CountSlashes(path)) { + } + if (!isdir && (mntpt[0] == '\0') && !CountSlashes(path)) { #ifdef ANDROID /* * When mounting the ZIP archive on the root directory try * to remap top level regular files of the archive to * /assets/.root/... since this directory should not be @@ -1263,122 +1199,121 @@ Tcl_DStringInit(&ds2); Tcl_DStringAppend(&ds2, "assets/.root/", -1); Tcl_DStringAppend(&ds2, path, -1); hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, Tcl_DStringValue(&ds2)); if (hPtr != NULL) { - /* should not happen but skip it anyway */ - Tcl_DStringFree(&ds2); - goto nextent; + /* should not happen but skip it anyway */ + Tcl_DStringFree(&ds2); + goto nextent; } Tcl_DStringSetLength(&ds, 0); Tcl_DStringAppend(&ds, Tcl_DStringValue(&ds2), - Tcl_DStringLength(&ds2)); + Tcl_DStringLength(&ds2)); path = Tcl_DStringValue(&ds); Tcl_DStringFree(&ds2); #else - /* - * Regular files skipped when mounting on root. - */ - goto nextent; + /* + * Regular files skipped when mounting on root. + */ + goto nextent; #endif - } - Tcl_DStringSetLength(&fpBuf, 0); - fullpath = CanonicalPath(mntpt, path, &fpBuf, 1); - z = (ZipEntry *) Tcl_Alloc(sizeof (*z)); - z->name = NULL; - z->tnext = NULL; - z->depth = CountSlashes(fullpath); - z->zipfile = zf; - z->isdir = isdir; - z->isenc = (zip_read_short(lq + ZIP_LOCAL_FLAGS_OFFS) & 1) + } + Tcl_DStringSetLength(&fpBuf, 0); + fullpath = CanonicalPath(mntpt, path, &fpBuf, 1); + z = (ZipEntry *) Tcl_Alloc(sizeof (*z)); + z->name = NULL; + z->tnext = NULL; + z->depth = CountSlashes(fullpath); + z->zipfile = zf; + z->isdir = isdir; + z->isenc = (zip_read_short(lq + ZIP_LOCAL_FLAGS_OFFS) & 1) && (nbcompr > 12); - z->offset = offs; - if (gq != NULL) { + z->offset = offs; + if (gq != NULL) { z->crc32 = zip_read_int(gq + ZIP_CENTRAL_CRC32_OFFS); dosDate = zip_read_short(gq + ZIP_CENTRAL_MDATE_OFFS); dosTime = zip_read_short(gq + ZIP_CENTRAL_MTIME_OFFS); z->timestamp = DosTimeDate(dosDate, dosTime); z->nbyte = zip_read_int(gq + ZIP_CENTRAL_UNCOMPLEN_OFFS); z->cmeth = zip_read_short(gq + ZIP_CENTRAL_COMPMETH_OFFS); - } else { + } else { z->crc32 = zip_read_int(lq + ZIP_LOCAL_CRC32_OFFS); dosDate = zip_read_short(lq + ZIP_LOCAL_MDATE_OFFS); dosTime = zip_read_short(lq + ZIP_LOCAL_MTIME_OFFS); z->timestamp = DosTimeDate(dosDate, dosTime); z->nbyte = zip_read_int(lq + ZIP_LOCAL_UNCOMPLEN_OFFS); z->cmeth = zip_read_short(lq + ZIP_LOCAL_COMPMETH_OFFS); - } - z->nbytecompr = nbcompr; - z->data = NULL; - hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, fullpath, &isNew); - if (!isNew) { + } + z->nbytecompr = nbcompr; + z->data = NULL; + hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, fullpath, &isNew); + if (!isNew) { /* should not happen but skip it anyway */ Tcl_Free((char *) z); - } else { + } else { Tcl_SetHashValue(hPtr, (ClientData) z); z->name = Tcl_GetHashKey(&ZipFS.fileHash, hPtr); z->next = zf->entries; zf->entries = z; if (isdir && (mntpt[0] == '\0') && (z->depth == 1)) { - z->tnext = zf->topents; - zf->topents = z; + z->tnext = zf->topents; + zf->topents = z; } if (!z->isdir && (z->depth > 1)) { - char *dir, *end; - ZipEntry *zd; - - Tcl_DStringSetLength(&ds, strlen(z->name) + 8); - Tcl_DStringSetLength(&ds, 0); - Tcl_DStringAppend(&ds, z->name, -1); - dir = Tcl_DStringValue(&ds); - end = strrchr(dir, '/'); - while ((end != NULL) && (end != dir)) { - Tcl_DStringSetLength(&ds, end - dir); - hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, dir); - if (hPtr != NULL) { - break; - } - zd = (ZipEntry *) Tcl_Alloc(sizeof (*zd)); - zd->name = NULL; - zd->tnext = NULL; - zd->depth = CountSlashes(dir); - zd->zipfile = zf; - zd->isdir = 1; - zd->isenc = 0; - zd->offset = z->offset; - zd->crc32 = 0; - zd->timestamp = z->timestamp; - zd->nbyte = zd->nbytecompr = 0; - zd->cmeth = ZIP_COMPMETH_STORED; - zd->data = NULL; - hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, dir, &isNew); - if (!isNew) { - /* should not happen but skip it anyway */ - Tcl_Free((char *) zd); - } else { - Tcl_SetHashValue(hPtr, (ClientData) zd); - zd->name = Tcl_GetHashKey(&ZipFS.fileHash, hPtr); - zd->next = zf->entries; - zf->entries = zd; - if ((mntpt[0] == '\0') && (zd->depth == 1)) { - zd->tnext = zf->topents; - zf->topents = zd; - } - } - end = strrchr(dir, '/'); - } - } - } + char *dir, *end; + ZipEntry *zd; + + Tcl_DStringSetLength(&ds, strlen(z->name) + 8); + Tcl_DStringSetLength(&ds, 0); + Tcl_DStringAppend(&ds, z->name, -1); + dir = Tcl_DStringValue(&ds); + end = strrchr(dir, '/'); + while ((end != NULL) && (end != dir)) { + Tcl_DStringSetLength(&ds, end - dir); + hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, dir); + if (hPtr != NULL) { + break; + } + zd = (ZipEntry *) Tcl_Alloc(sizeof (*zd)); + zd->name = NULL; + zd->tnext = NULL; + zd->depth = CountSlashes(dir); + zd->zipfile = zf; + zd->isdir = 1; + zd->isenc = 0; + zd->offset = z->offset; + zd->crc32 = 0; + zd->timestamp = z->timestamp; + zd->nbyte = zd->nbytecompr = 0; + zd->cmeth = ZIP_COMPMETH_STORED; + zd->data = NULL; + hPtr = Tcl_CreateHashEntry(&ZipFS.fileHash, dir, &isNew); + if (!isNew) { + /* should not happen but skip it anyway */ + Tcl_Free((char *) zd); + } else { + Tcl_SetHashValue(hPtr, (ClientData) zd); + zd->name = Tcl_GetHashKey(&ZipFS.fileHash, hPtr); + zd->next = zf->entries; + zf->entries = zd; + if ((mntpt[0] == '\0') && (zd->depth == 1)) { + zd->tnext = zf->topents; + zf->topents = zd; + } + } + end = strrchr(dir, '/'); + } + } + } nextent: - q += pathlen + comlen + extra + ZIP_CENTRAL_HEADER_LEN; - } - Unlock(); - Tcl_DStringFree(&fpBuf); - Tcl_DStringFree(&ds); - Tcl_DStringFree(&dsm); - Tcl_FSMountsChanged(NULL); - return TCL_OK; + q += pathlen + comlen + extra + ZIP_CENTRAL_HEADER_LEN; + } + Unlock(); + Tcl_DStringFree(&fpBuf); + Tcl_DStringFree(&ds); + Tcl_FSMountsChanged(NULL); + return TCL_OK; } /* *------------------------------------------------------------------------- * @@ -1396,59 +1331,54 @@ */ int TclZipfs_Unmount(Tcl_Interp *interp, const char *zipname) { - char *realname; - ZipFile *zf; - ZipEntry *z, *znext; - Tcl_HashEntry *hPtr; - Tcl_DString ds; - int ret = TCL_OK, unmounted = 0; - - Tcl_DStringInit(&ds); - realname = AbsolutePath(zipname, &ds, 0); - WriteLock(); - if (!ZipFS.initialized) { - goto done; - } - hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, realname); - if (hPtr == NULL) { - /* don't report error */ - goto done; - } - zf = (ZipFile *) Tcl_GetHashValue(hPtr); - if (zf->nopen > 0) { - if (interp != NULL) { + ZipFile *zf; + ZipEntry *z, *znext; + Tcl_HashEntry *hPtr; + int ret = TCL_OK, unmounted = 0; + + WriteLock(); + if (!ZipFS.initialized) { + goto done; + } + hPtr = Tcl_FindHashEntry(&ZipFS.zipHash, zipname); + if (hPtr == NULL) { + /* don't report error */ + goto done; + } + zf = (ZipFile *) Tcl_GetHashValue(hPtr); + if (zf->nopen > 0) { + if (interp != NULL) { Tcl_SetObjResult(interp, - Tcl_NewStringObj("filesystem is busy", -1)); - } - ret = TCL_ERROR; - goto done; - } - Tcl_DeleteHashEntry(hPtr); - for (z = zf->entries; z; z = znext) { - znext = z->next; - hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, z->name); - if (hPtr) { - Tcl_DeleteHashEntry(hPtr); - } - if (z->data != NULL) { + Tcl_NewStringObj("filesystem is busy", -1)); + } + ret = TCL_ERROR; + goto done; + } + Tcl_DeleteHashEntry(hPtr); + for (z = zf->entries; z; z = znext) { + znext = z->next; + hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, z->name); + if (hPtr) { + Tcl_DeleteHashEntry(hPtr); + } + if (z->data != NULL) { Tcl_Free((char *) z->data); + } + Tcl_Free((char *) z); } - Tcl_Free((char *) z); - } - ZipFSCloseArchive(interp, zf); - Tcl_Free((char *) zf); - unmounted = 1; + ZipFSCloseArchive(interp, zf); + Tcl_Free((char *) zf); + unmounted = 1; done: - Unlock(); - Tcl_DStringFree(&ds); - if (unmounted) { - Tcl_FSMountsChanged(NULL); - } - return ret; + Unlock(); + if (unmounted) { + Tcl_FSMountsChanged(NULL); + } + return ret; } /* *------------------------------------------------------------------------- * @@ -2248,38 +2178,38 @@ static int ZipFSCanonicalObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { - char *mntpoint=NULL; - char *filename=NULL; - char *result; - Tcl_DString dPath; - - if (objc != 2 && objc != 3 && objc!=4) { - Tcl_WrongNumArgs(interp, 1, objv, "?mntpnt? filename ?ZIPFS?"); - return TCL_ERROR; - } - Tcl_DStringInit(&dPath); - if(objc==2) { - filename = Tcl_GetString(objv[1]); - result=CanonicalPath("",filename,&dPath,1); - } else if (objc==3) { - mntpoint = Tcl_GetString(objv[1]); - filename = Tcl_GetString(objv[2]); - result=CanonicalPath(mntpoint,filename,&dPath,1); - } else { - int zipfs=0; - if(Tcl_GetBooleanFromObj(interp,objv[3],&zipfs)) { - return TCL_ERROR; - } - mntpoint = Tcl_GetString(objv[1]); - filename = Tcl_GetString(objv[2]); - result=CanonicalPath(mntpoint,filename,&dPath,zipfs); - } - Tcl_SetObjResult(interp,Tcl_NewStringObj(result,-1)); - return TCL_OK; + char *mntpoint=NULL; + char *filename=NULL; + char *result; + Tcl_DString dPath; + + if (objc != 2 && objc != 3 && objc!=4) { + Tcl_WrongNumArgs(interp, 1, objv, "?mntpnt? filename ?ZIPFS?"); + return TCL_ERROR; + } + Tcl_DStringInit(&dPath); + if(objc==2) { + filename = Tcl_GetString(objv[1]); + result=CanonicalPath("",filename,&dPath,1); + } else if (objc==3) { + mntpoint = Tcl_GetString(objv[1]); + filename = Tcl_GetString(objv[2]); + result=CanonicalPath(mntpoint,filename,&dPath,1); + } else { + int zipfs=0; + if(Tcl_GetBooleanFromObj(interp,objv[3],&zipfs)) { + return TCL_ERROR; + } + mntpoint = Tcl_GetString(objv[1]); + filename = Tcl_GetString(objv[2]); + result=CanonicalPath(mntpoint,filename,&dPath,zipfs); + } + Tcl_SetObjResult(interp,Tcl_NewStringObj(result,-1)); + return TCL_OK; } /* *------------------------------------------------------------------------- * @@ -2302,19 +2232,28 @@ ZipFSExistsObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { char *filename; int exists; + Tcl_DString ds; if (objc != 2) { Tcl_WrongNumArgs(interp, 1, objv, "filename"); return TCL_ERROR; } + + /* prepend ZIPFS_VOLUME to filename, eliding the final / */ filename = Tcl_GetStringFromObj(objv[1], 0); + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, ZIPFS_VOLUME, ZIPFS_VOLUME_LEN-1); + Tcl_DStringAppend(&ds, filename, -1); + filename = Tcl_DStringValue(&ds); + ReadLock(); exists = ZipFSLookup(filename) != NULL; Unlock(); + Tcl_SetObjResult(interp,Tcl_NewBooleanObj(exists)); return TCL_OK; } /* @@ -2773,10 +2712,11 @@ WriteLock(); z = ZipFSLookup(filename); if (z == NULL) { if (interp != NULL) { Tcl_SetObjResult(interp, Tcl_NewStringObj("file not found", -1)); + Tcl_AppendResult(interp, " \"", filename, "\"", NULL); } goto error; } trunc = (mode & O_TRUNC) != 0; wr = (mode & (O_WRONLY | O_RDWR)) != 0; @@ -3154,10 +3094,12 @@ Zip_FSOpenFileChannelProc(Tcl_Interp *interp, Tcl_Obj *pathPtr, int mode, int permissions) { int len; + if (!(pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return NULL; + return ZipChannelOpen(interp, Tcl_GetStringFromObj(pathPtr, &len), mode, permissions); } /* @@ -3180,10 +3122,12 @@ static int Zip_FSStatProc(Tcl_Obj *pathPtr, Tcl_StatBuf *buf) { int len; + if (!(pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return -1; + return ZipEntryStat(Tcl_GetStringFromObj(pathPtr, &len), buf); } /* *------------------------------------------------------------------------- @@ -3204,10 +3148,12 @@ static int Zip_FSAccessProc(Tcl_Obj *pathPtr, int mode) { int len; + + if (!(pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return -1; return ZipEntryAccess(Tcl_GetStringFromObj(pathPtr, &len), mode); } /* @@ -3256,152 +3202,158 @@ static int Zip_FSMatchInDirectoryProc(Tcl_Interp* interp, Tcl_Obj *result, Tcl_Obj *pathPtr, const char *pattern, Tcl_GlobTypeData *types) { - Tcl_HashEntry *hPtr; - Tcl_HashSearch search; - int scnt, len, l, dirOnly = -1, prefixLen, strip = 0; - char *pat, *prefix, *path; - Tcl_DString ds, dsPref; - if (types != NULL) { - dirOnly = (types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR; - } - Tcl_DStringInit(&ds); - Tcl_DStringInit(&dsPref); - prefix = Tcl_GetStringFromObj(pathPtr, &prefixLen); - Tcl_DStringAppend(&dsPref, prefix, prefixLen); - prefix = Tcl_DStringValue(&dsPref); - path = AbsolutePath(prefix, &ds, 1); - len = Tcl_DStringLength(&ds); - if (strcmp(prefix, path) == 0) { - prefix = NULL; - } else { - strip = len + 1; - } - if (prefix != NULL) { - Tcl_DStringAppend(&dsPref, "/", 1); - prefixLen++; - prefix = Tcl_DStringValue(&dsPref); - } - ReadLock(); - if ((types != NULL) && (types->type == TCL_GLOB_TYPE_MOUNT)) { - l = CountSlashes(path); - if (path[len - 1] == '/') { + Tcl_HashEntry *hPtr; + Tcl_HashSearch search; + Tcl_Obj *normPathPtr; + int scnt, len, l, dirOnly = -1, prefixLen, strip = 0; + char *pat, *prefix, *path; + Tcl_DString dsPref; + + if (!(normPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return -1; + + if (types != NULL) { + dirOnly = (types->type & TCL_GLOB_TYPE_DIR) == TCL_GLOB_TYPE_DIR; + } + + /* the prefix that gets prepended to results */ + prefix = Tcl_GetStringFromObj(pathPtr, &prefixLen); + + /* the (normalized) path we're searching */ + path = Tcl_GetStringFromObj(normPathPtr, &len); + + Tcl_DStringInit(&dsPref); + Tcl_DStringAppend(&dsPref, prefix, prefixLen); + + if (strcmp(prefix, path) == 0) { + prefix = NULL; + } else { + strip = len + 1; + } + if (prefix != NULL) { + Tcl_DStringAppend(&dsPref, "/", 1); + prefixLen++; + prefix = Tcl_DStringValue(&dsPref); + } + ReadLock(); + if ((types != NULL) && (types->type == TCL_GLOB_TYPE_MOUNT)) { + l = CountSlashes(path); + if (path[len - 1] == '/') { len--; - } else { + } else { l++; - } - if ((pattern == NULL) || (pattern[0] == '\0')) { + } + if ((pattern == NULL) || (pattern[0] == '\0')) { pattern = "*"; - } - hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); - while (hPtr != NULL) { + } + hPtr = Tcl_FirstHashEntry(&ZipFS.zipHash, &search); + while (hPtr != NULL) { ZipFile *zf = (ZipFile *) Tcl_GetHashValue(hPtr); if (zf->mntptlen == 0) { - ZipEntry *z = zf->topents; - while (z != NULL) { - int lenz = strlen(z->name); - if ((lenz > len + 1) && - (strncmp(z->name, path, len) == 0) && - (z->name[len] == '/') && - (CountSlashes(z->name) == l) && - Tcl_StringCaseMatch(z->name + len + 1, pattern, 0)) { - if (prefix != NULL) { - Tcl_DStringAppend(&dsPref, z->name, lenz); - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(Tcl_DStringValue(&dsPref), - Tcl_DStringLength(&dsPref))); - Tcl_DStringSetLength(&dsPref, prefixLen); - } else { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(z->name, lenz)); - } - } - z = z->tnext; - } + ZipEntry *z = zf->topents; + while (z != NULL) { + int lenz = strlen(z->name); + if ((lenz > len + 1) && + (strncmp(z->name, path, len) == 0) && + (z->name[len] == '/') && + (CountSlashes(z->name) == l) && + Tcl_StringCaseMatch(z->name + len + 1, pattern, 0)) { + if (prefix != NULL) { + Tcl_DStringAppend(&dsPref, z->name, lenz); + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(Tcl_DStringValue(&dsPref), + Tcl_DStringLength(&dsPref))); + Tcl_DStringSetLength(&dsPref, prefixLen); + } else { + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(z->name, lenz)); + } + } + z = z->tnext; + } } else if ((zf->mntptlen > len + 1) && - (strncmp(zf->mntpt, path, len) == 0) && - (zf->mntpt[len] == '/') && - (CountSlashes(zf->mntpt) == l) && - Tcl_StringCaseMatch(zf->mntpt + len + 1, pattern, 0)) { - if (prefix != NULL) { - Tcl_DStringAppend(&dsPref, zf->mntpt, zf->mntptlen); - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(Tcl_DStringValue(&dsPref), - Tcl_DStringLength(&dsPref))); - Tcl_DStringSetLength(&dsPref, prefixLen); - } else { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(zf->mntpt, zf->mntptlen)); - } + (strncmp(zf->mntpt, path, len) == 0) && + (zf->mntpt[len] == '/') && + (CountSlashes(zf->mntpt) == l) && + Tcl_StringCaseMatch(zf->mntpt + len + 1, pattern, 0)) { + if (prefix != NULL) { + Tcl_DStringAppend(&dsPref, zf->mntpt, zf->mntptlen); + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(Tcl_DStringValue(&dsPref), + Tcl_DStringLength(&dsPref))); + Tcl_DStringSetLength(&dsPref, prefixLen); + } else { + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(zf->mntpt, zf->mntptlen)); + } } hPtr = Tcl_NextHashEntry(&search); + } + goto end; } - goto end; - } - if ((pattern == NULL) || (pattern[0] == '\0')) { - hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, path); - if (hPtr != NULL) { + if ((pattern == NULL) || (pattern[0] == '\0')) { + hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, path); + if (hPtr != NULL) { ZipEntry *z = (ZipEntry *) Tcl_GetHashValue(hPtr); if ((dirOnly < 0) || - (!dirOnly && !z->isdir) || - (dirOnly && z->isdir)) { - if (prefix != NULL) { - Tcl_DStringAppend(&dsPref, z->name, -1); - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(Tcl_DStringValue(&dsPref), - Tcl_DStringLength(&dsPref))); - Tcl_DStringSetLength(&dsPref, prefixLen); - } else { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(z->name, -1)); - } - } - } - goto end; - } - l = strlen(pattern); - pat = Tcl_Alloc(len + l + 2); - memcpy(pat, path, len); - while ((len > 1) && (pat[len - 1] == '/')) { - --len; - } - if ((len > 1) || (pat[0] != '/')) { - pat[len] = '/'; - ++len; - } - memcpy(pat + len, pattern, l + 1); - scnt = CountSlashes(pat); - for (hPtr = Tcl_FirstHashEntry(&ZipFS.fileHash, &search); - hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { - ZipEntry *z = (ZipEntry *) Tcl_GetHashValue(hPtr); - if ((dirOnly >= 0) && - ((dirOnly && !z->isdir) || (!dirOnly && z->isdir))) { + (!dirOnly && !z->isdir) || + (dirOnly && z->isdir)) { + if (prefix != NULL) { + Tcl_DStringAppend(&dsPref, z->name, -1); + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(Tcl_DStringValue(&dsPref), + Tcl_DStringLength(&dsPref))); + Tcl_DStringSetLength(&dsPref, prefixLen); + } else { + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(z->name, -1)); + } + } + } + goto end; + } + l = strlen(pattern); + pat = Tcl_Alloc(len + l + 2); + memcpy(pat, path, len); + while ((len > 1) && (pat[len - 1] == '/')) { + --len; + } + if ((len > 1) || (pat[0] != '/')) { + pat[len] = '/'; + ++len; + } + memcpy(pat + len, pattern, l + 1); + scnt = CountSlashes(pat); + for (hPtr = Tcl_FirstHashEntry(&ZipFS.fileHash, &search); + hPtr != NULL; hPtr = Tcl_NextHashEntry(&search)) { + ZipEntry *z = (ZipEntry *) Tcl_GetHashValue(hPtr); + if ((dirOnly >= 0) && + ((dirOnly && !z->isdir) || (!dirOnly && z->isdir))) { continue; - } - if ((z->depth == scnt) && Tcl_StringCaseMatch(z->name, pat, 0)) { - if (prefix != NULL) { - Tcl_DStringAppend(&dsPref, z->name + strip, -1); - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(Tcl_DStringValue(&dsPref), - Tcl_DStringLength(&dsPref))); - Tcl_DStringSetLength(&dsPref, prefixLen); - } else { - Tcl_ListObjAppendElement(NULL, result, - Tcl_NewStringObj(z->name + strip, -1)); - } - } - } - Tcl_Free(pat); -end: - Unlock(); - Tcl_DStringFree(&dsPref); - Tcl_DStringFree(&ds); - return TCL_OK; + } + if ((z->depth == scnt) && Tcl_StringCaseMatch(z->name, pat, 0)) { + if (prefix != NULL) { + Tcl_DStringAppend(&dsPref, z->name + strip, -1); + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(Tcl_DStringValue(&dsPref), + Tcl_DStringLength(&dsPref))); + Tcl_DStringSetLength(&dsPref, prefixLen); + } else { + Tcl_ListObjAppendElement(NULL, result, + Tcl_NewStringObj(z->name + strip, -1)); + } + } + } + Tcl_Free(pat); +end: + Unlock(); + Tcl_DStringFree(&dsPref); + return TCL_OK; } /* *------------------------------------------------------------------------- * @@ -3425,20 +3377,20 @@ Tcl_HashEntry *hPtr; Tcl_HashSearch search; ZipFile *zf; int ret = -1, len; char *path; - Tcl_DString ds; + + if (!(pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return -1; path = Tcl_GetStringFromObj(pathPtr, &len); if(strncmp(path,ZIPFS_VOLUME,ZIPFS_VOLUME_LEN)!=0) { return -1; } - Tcl_DStringInit(&ds); - path = CanonicalPath("",path, &ds, 1); - len = Tcl_DStringLength(&ds); + len = strlen(path); + ReadLock(); hPtr = Tcl_FindHashEntry(&ZipFS.fileHash, path); if (hPtr != NULL) { ret = TCL_OK; goto endloop; @@ -3465,11 +3417,10 @@ } hPtr = Tcl_NextHashEntry(&search); } endloop: Unlock(); - Tcl_DStringFree(&ds); return ret; } /* *------------------------------------------------------------------------- @@ -3486,11 +3437,11 @@ * *------------------------------------------------------------------------- */ static Tcl_Obj * Zip_FSListVolumesProc(void) { - return Tcl_NewStringObj(ZIPFS_VOLUME, -1); + return Tcl_NewStringObj(ZIPFS_VOLUME, -1); } /* *------------------------------------------------------------------------- * @@ -3549,10 +3500,12 @@ Tcl_Obj **objPtrRef) { int len, ret = TCL_OK; char *path; ZipEntry *z; + + if (!(pathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr))) return -1; path = Tcl_GetStringFromObj(pathPtr, &len); ReadLock(); z = ZipFSLookup(path); if (z == NULL) { Index: tests/zipfs.test ================================================================== --- tests/zipfs.test +++ tests/zipfs.test @@ -16,73 +16,116 @@ } testConstraint zipfs [expr {[llength [info commands zlib]] && [regexp tcltest [info nameofexecutable]]}] # Removed in tip430 - zipfs is no longer a static package -#test zipfs-1.1 {zipfs basics} -constraints zipfs -body { +#test zipfs-0.0 {zipfs basics} -constraints zipfs -body { # load {} zipfs #} -result {} -test zipfs-1.2 {zipfs basics} -constraints zipfs -body { +test zipfs-0.1 {zipfs basics} -constraints zipfs -body { package require zipfs } -result {1.0} -test zipfs-1.3 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-0.1 {zipfs basics} -constraints zipfs -body { + expr {"//zipfs:/" in [file volumes]} +} -result 1 + +test zipfs-0.2 {zipfs basics} -constraints zipfs -body { + string match //zipfs:/* $tcl_library +} -result 1 + +test zipfs-0.3 {zipfs basics: glob} -constraints zipfs -body { + set pwd [pwd] + cd $tcl_library + lsort [glob -dir . http*] +} -cleanup { + cd $pwd +} -result {./http ./http1.0} + +test zipfs-0.4 {zipfs basics: glob} -constraints zipfs -body { + set pwd [pwd] + cd $tcl_library + lsort [glob -dir [pwd] http*] +} -cleanup { + cd $pwd +} -result [list $tcl_library/http $tcl_library/http1.0] + +test zipfs-0.5 {zipfs basics: glob} -constraints zipfs -body { + lsort [glob -dir $tcl_library http*] +} -result [list $tcl_library/http $tcl_library/http1.0] + +test zipfs-0.6 {zipfs basics: glob} -constraints zipfs -body { + lsort [glob $tcl_library/http*] +} -result [list $tcl_library/http $tcl_library/http1.0] + +test zipfs-0.7 {zipfs basics: glob} -constraints zipfs -body { + lsort [glob -tails -dir $tcl_library http*] +} -result {http http1.0} + +test zipfs-0.8 {zipfs basics: glob} -constraints zipfs -body { + lsort [glob -nocomplain -tails -types d -dir $tcl_library http*] +} -result {http http1.0} + +test zipfs-0.9 {zipfs basics: glob} -constraints zipfs -body { + lsort [glob -nocomplain -tails -types f -dir $tcl_library http*] +} -result {} + + +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?"} -test zipfs-1.4 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.4 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs unmount a b c d e f } -result {wrong # args: should be "zipfs unmount zipfile"} -test zipfs-1.5 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.5 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs mkkey a b c d e f } -result {wrong # args: should be "zipfs mkkey password"} -test zipfs-1.6 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.6 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs mkimg a b c d e f } -result {wrong # args: should be "zipfs mkimg outfile indir ?strip? ?password? ?infile?"} -test zipfs-1.7 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.7 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs mkzip a b c d e f } -result {wrong # args: should be "zipfs mkzip outfile indir ?strip? ?password?"} -test zipfs-1.8 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.8 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs exists a b c d e f } -result {wrong # args: should be "zipfs exists filename"} -test zipfs-1.9 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.9 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs info a b c d e f } -result {wrong # args: should be "zipfs info filename"} -test zipfs-1.10 {zipfs basics} -constraints zipfs -returnCodes error -body { +test zipfs-1.10 {zipfs errors} -constraints zipfs -returnCodes error -body { zipfs list a b c d e f } -result {wrong # args: should be "zipfs list ?(-glob|-regexp)? ?pattern?"} -set ntcl_library [file normalize $tcl_library] - test zipfs-2.1 {zipfs mkzip empty archive} -constraints zipfs -returnCodes error -body { - zipfs mkzip abc.zip $ntcl_library/xxxx + zipfs mkzip /tmp/abc.zip $tcl_library/xxxx ;# FIXME: test independence } -result {empty archive} test zipfs-2.2 {zipfs mkzip} -constraints zipfs -body { set pwd [pwd] - cd $ntcl_library/encoding - zipfs mkzip abc.zip . - zipfs mount abc.zip zipfs:/abc - zipfs list -glob zipfs:/abc/cp850.* + cd $tcl_library/encoding + zipfs mkzip /tmp/abc.zip . + zipfs mount /tmp/abc.zip //zipfs:/abc ;# FIXME: test independence + zipfs list -glob //zipfs:/abc/cp850.* } -cleanup { cd $pwd -} -result {zipfs:/abc/cp850.enc} - -test zipfs-2.3 {zipfs unmount} -constraints zipfs -body { - zipfs info zipfs:/abc/cp850.enc -} -result [list $ntcl_library/encoding/abc.zip 1090 527 39434] - -test zipfs-2.4 {zipfs unmount} -constraints zipfs -body { - set f [open zipfs:/abc/cp850.enc] - read $f +} -result {//zipfs:/abc/cp850.enc} + +test zipfs-2.3 {zipfs info} -constraints zipfs -body { + zipfs info //zipfs:/abc/cp850.enc +} -result [list /tmp/abc.zip 1090 527 39318] ;# FIXME: result depends on content of encodings dir + +test zipfs-2.4 {zipfs data} -constraints zipfs -body { + set zipfd [open //zipfs:/abc/cp850.enc] ;# FIXME: leave open - see later test + read $zipfd } -result {# Encoding file: cp850, single-byte S 003F 0 1 00 0000000100020003000400050006000700080009000A000B000C000D000E000F @@ -99,20 +142,29 @@ 2591259225932502252400C100C200C000A9256325512557255D00A200A52510 25142534252C251C2500253C00E300C3255A25542569256625602550256C00A4 00F000D000CA00CB00C8013100CD00CE00CF2518250C2588258400A600CC2580 00D300DF00D400D200F500D500B500FE00DE00DA00DB00D900FD00DD00AF00B4 00AD00B1201700BE00B600A700F700B800B000A800B700B900B300B225A000A0 -} +} ;# FIXME: result depends on content of encodings dir test zipfs-2.5 {zipfs exists} -constraints zipfs -body { - zipfs unmount abc.zip + zipfs exists /abc/cp850.enc +} -result 1 + +test zipfs-2.6 {zipfs unmount while busy} -constraints zipfs -body { + zipfs unmount /tmp/abc.zip +} -returnCodes error -result {filesystem is busy} + +test zipfs-2.7 {zipfs unmount} -constraints zipfs -body { + close $zipfd + zipfs unmount /tmp/abc.zip zipfs exists /abc/cp850.enc } -cleanup { - file delete abc.zip -} -result 1 + file delete /tmp/abc.zip ;# FIXME: test independence +} -result 0 ::tcltest::cleanupTests return # Local Variables: # mode: tcl # End: