Tcl Source Code

Check-in [da3a746b1d]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Make ready for TIP #494 compatibility
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core_zip_vfs-review
Files: files | file ages | folders
SHA3-256: da3a746b1d47f348334d53647429104a8e10660929b7f22faac690ae13f80700
User & Date: jan.nijtmans 2018-09-11 22:41:00
Context
2018-09-12
19:32
Stub fix, safe interpreter fix, and use more size_t wherever possible check-in: 5f80f9af59 user: jan.nijtmans tags: core-8-branch
2018-09-11
22:41
Make ready for TIP #494 compatibility Closed-Leaf check-in: da3a746b1d user: jan.nijtmans tags: core_zip_vfs-review
2018-09-09
17:05
slightly better: Use GetFileSizeEx() on win64 and GetFileSize on win32 check-in: d199aeb4b6 user: jan.nijtmans tags: core_zip_vfs-review
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclZipfs.c.

182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
....
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
....
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
....
1915
1916
1917
1918
1919
1920
1921

1922

1923
1924
1925
1926
1927
1928
1929
1930
....
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
....
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
....
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
....
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
....
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132

2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
....
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
....
2232
2233
2234
2235
2236
2237
2238
2239


2240
2241
2242
2243
2244
2245
2246
....
2381
2382
2383
2384
2385
2386
2387

2388
2389
2390
2391
2392
2393
2394
2395
....
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
....
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
....
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
....
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
....
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
....
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
....
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
....
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
....
4403
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
#if defined(_WIN32) || defined(_WIN64)
    HANDLE mh;
#endif
    size_t nopen;             /* Number of open files on archive */
    struct ZipEntry *entries; /* List of files in archive */
    struct ZipEntry *topents; /* List of top-level dirs in archive */
#if HAS_DRIVES
    int mntdrv;                  /* Drive letter of mount point */
#endif
    size_t mntptlen;
    char *mntpt;              /* Mount point */
} ZipFile;

/*
 * In-core description of file contained in mounted ZIP archive.
 */

typedef struct ZipEntry {
    char *name;               /* The full pathname of the virtual file */
    ZipFile *zipfile;         /* The ZIP file holding this virtual file */
    long offset;              /* Data offset into memory mapped ZIP file */
    int nbyte;                /* Uncompressed size of the virtual file */
    int nbytecompr;           /* Compressed size of the virtual file */
    int cmeth;                /* Compress method */
    int isdir;                  /* Set to 1 if directory, or -1 if root */
    int depth;                   /* Number of slashes in path. */
    int crc32;                /* CRC-32 */
    int timestamp;            /* Modification time */
................................................................................
    ZipFile *zipfile;         /* The ZIP file holding this channel */
    ZipEntry *zipentry;       /* Pointer back to virtual file */
    size_t nmax;              /* Max. size for write */
    size_t nbyte;             /* Number of bytes of uncompressed data */
    size_t nread;             /* Pos of next byte to be read from the channel */
    unsigned char *ubuf;      /* Pointer to the uncompressed data */
    int iscompr;              /* True if data is compressed */
    int isdir;                  /* Set to 1 if directory, or -1 if root */
    int isenc;                /* True if data is encrypted */
    int iswr;                 /* True if open for writing */
    unsigned long keys[3];    /* Key for decryption */
} ZipChannel;

/*
 * Global variables.
................................................................................
        if (Tcl_SetChannelOption(interp, zf->chan, "-translation", "binary") != TCL_OK) {
            goto error;
        }
        if (Tcl_SetChannelOption(interp, zf->chan, "-encoding", "binary") != TCL_OK) {
            goto error;
        }
        zf->length = Tcl_Seek(zf->chan, 0, SEEK_END);
        if ((zf->length < ZIP_CENTRAL_END_LEN) || (zf->length > 64 * 1024 * 1024)) {
            ZIPFS_ERROR(interp,"illegal file size");
            goto error;
        }
        Tcl_Seek(zf->chan, 0, SEEK_SET);
        zf->tofree = zf->data = (unsigned char *) Tcl_AttemptAlloc(zf->length);
        if (zf->tofree == NULL) {
            ZIPFS_ERROR(interp,"out of memory")
................................................................................
        if (i != zf->length) {
            ZIPFS_ERROR(interp,"file read error");
            goto error;
        }
        Tcl_Close(interp, zf->chan);
        zf->chan = NULL;
    } else {
#ifdef _WIN32)
#   ifdef _WIN64
        i = GetFileSizeEx((HANDLE) handle, (PLARGE_INTEGER)&zf->length);
        if (
            (i == 0) ||
#   else
        zf->length = GetFileSize((HANDLE) handle, 0);
        if (
................................................................................
    char *buf, int bufsize, Tcl_HashTable *fileHash
) {
    Tcl_Channel in;
    Tcl_HashEntry *hPtr;
    ZipEntry *z;
    z_stream stream;
    const char *zpath;

    int nbyte, nbytecompr, len, crc, flush, pos[3], zpathlen, olen;

    int mtime = 0, isNew, align = 0, cmeth;
    unsigned long keys[3], keys0[3];
    char obuf[4096];

    zpath = name;
    while (zpath != NULL && zpath[0] == '/') {
        zpath++;
    }
................................................................................
            mtime = statBuf.st_mtime;
        }
        Tcl_DecrRefCount(pathObj);
    }
    Tcl_ResetResult(interp);
    crc = 0;
    nbyte = nbytecompr = 0;
    while ((len = Tcl_Read(in, buf, bufsize)) > 0) {
        crc = crc32(crc, (unsigned char *) buf, len);
        nbyte += len;
    }
    if (len == -1) {
        if (nbyte == 0) {
            if (strcmp("illegal operation on a directory",
                   Tcl_PosixError(interp)) == 0) {
            Tcl_Close(interp, in);
            return TCL_OK;
            }
        }
................................................................................
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    pos[0] = Tcl_Tell(out);
    memset(buf, '\0', ZIP_LOCAL_HEADER_LEN);
    memcpy(buf + ZIP_LOCAL_HEADER_LEN, zpath, zpathlen);
    len = zpathlen + ZIP_LOCAL_HEADER_LEN;
    if (Tcl_Write(out, buf, len) != len) {
wrerr:
    Tcl_AppendResult(interp, "write error", (char *) NULL);
    Tcl_Close(interp, in);
    return TCL_ERROR;
    }
    if ((len + pos[0]) & 3) {
        unsigned char abuf[8];
................................................................................
         * Align payload to next 4-byte boundary using a dummy extra
         * entry similar to the zipalign tool from Android's SDK.
         */
        align = 4 + ((len + pos[0]) & 3);
        zip_write_short(abuf, 0xffff);
        zip_write_short(abuf + 2, align - 4);
        zip_write_int(abuf + 4, 0x03020100);
        if (Tcl_Write(out, (const char *)abuf, align) != align) {
            goto wrerr;
        }
    }
    if (passwd != NULL) {
        int i, ch, tmp;
        unsigned char kvbuf[24];
        Tcl_Obj *ret;
................................................................................
        Tcl_AppendResult(interp, "compression init error on \"", path, "\"",
                 (char *) NULL);
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    do {
    len = Tcl_Read(in, buf, bufsize);
    if (len == -1) {
        Tcl_AppendResult(interp, "read error on \"", path, "\"",
                 (char *) NULL);
        deflateEnd(&stream);
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    stream.avail_in = len;
    stream.next_in = (unsigned char *) buf;
    flush = Tcl_Eof(in) ? Z_FINISH : Z_NO_FLUSH;
    do {
        stream.avail_out = sizeof (obuf);
        stream.next_out = (unsigned char *) obuf;
        len = deflate(&stream, flush);
        if (len == Z_STREAM_ERROR) {
            Tcl_AppendResult(interp, "deflate error on \"", path, "\"",
                     (char *) NULL);
            deflateEnd(&stream);
            Tcl_Close(interp, in);
            return TCL_ERROR;
        }
        olen = sizeof (obuf) - stream.avail_out;
................................................................................
        /*
         * Compressed file larger than input,
         * write it again uncompressed.
         */
        if (Tcl_Seek(in, 0, SEEK_SET) != 0) {
            goto seekErr;
        }
        if ((int) Tcl_Seek(out, pos[2], SEEK_SET) != pos[2]) {
seekErr:
            Tcl_Close(interp, in);
            Tcl_AppendResult(interp, "seek error", (char *) NULL);
            return TCL_ERROR;
        }
        nbytecompr = (passwd != NULL) ? 12 : 0;
        while (1) {
            len = Tcl_Read(in, buf, bufsize);
            if (len == -1) {
            Tcl_AppendResult(interp, "read error on \"", path, "\"",
                     (char *) NULL);
            Tcl_Close(interp, in);
            return TCL_ERROR;
            } else if (len == 0) {
            break;
            }
            if (passwd != NULL) {

            int i, tmp;

            for (i = 0; i < len; i++) {
                buf[i] = (char) zencode(keys0, crc32tab, buf[i], tmp);
            }
            }
            if (Tcl_Write(out, buf, len) != len) {
            Tcl_AppendResult(interp, "write error", (char *) NULL);
            Tcl_Close(interp, in);
            return TCL_ERROR;
            }
            nbytecompr += len;
        }
        cmeth = ZIP_COMPMETH_STORED;
................................................................................
    zip_write_short(buf + ZIP_LOCAL_MTIME_OFFS, ToDosTime(z->timestamp));
    zip_write_short(buf + ZIP_LOCAL_MDATE_OFFS, ToDosDate(z->timestamp));
    zip_write_int(buf + ZIP_LOCAL_CRC32_OFFS, z->crc32);
    zip_write_int(buf + ZIP_LOCAL_COMPLEN_OFFS, z->nbytecompr);
    zip_write_int(buf + ZIP_LOCAL_UNCOMPLEN_OFFS, z->nbyte);
    zip_write_short(buf + ZIP_LOCAL_PATHLEN_OFFS, zpathlen);
    zip_write_short(buf + ZIP_LOCAL_EXTRALEN_OFFS, align);
    if ((int) Tcl_Seek(out, pos[0], SEEK_SET) != pos[0]) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "seek error", (char *) NULL);
        return TCL_ERROR;
    }
    if (Tcl_Write(out, buf, ZIP_LOCAL_HEADER_LEN) != ZIP_LOCAL_HEADER_LEN) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "write error", (char *) NULL);
        return TCL_ERROR;
    }
    Tcl_Flush(out);
    if ((int) Tcl_Seek(out, pos[1], SEEK_SET) != pos[1]) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "seek error", (char *) NULL);
        return TCL_ERROR;
    }
    return TCL_OK;
}
................................................................................
 */

static int
ZipFSMkZipOrImgObjCmd(ClientData clientData, Tcl_Interp *interp,
                      int isImg, int isList, int objc, Tcl_Obj *const objv[])
{
    Tcl_Channel out;
    int len = 0, pwlen = 0, slen = 0, i, count, ret = TCL_ERROR, lobjc, pos[3];


    Tcl_Obj **lobjv, *list = NULL;
    ZipEntry *z;
    Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_HashTable fileHash;
    char *strip = NULL, *pw = NULL, pwbuf[264], buf[4096];

................................................................................
                ZipFSCloseArchive(interp, zf);
            } else {
                WriteLock();
                zf->nopen--;
                Unlock();
            }
        } else {

            int k, m, n;
            Tcl_Channel in;
            const char *errMsg = "seek error";

            /*
             * Fall back to read it as plain file which
             * hopefully is a static tclsh or wish binary
             * with proper zipfs infrastructure built in.
................................................................................
                Tcl_DecrRefCount(list);
                Tcl_Close(interp, out);
                return TCL_ERROR;
            }
            Tcl_SetChannelOption(interp, in, "-translation", "binary");
            Tcl_SetChannelOption(interp, in, "-encoding", "binary");
            i = Tcl_Seek(in, 0, SEEK_END);
            if (i == -1) {
cperr:
                memset(pwbuf, 0, sizeof (pwbuf));
                Tcl_DecrRefCount(list);
                Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, -1));
                Tcl_Close(interp, out);
                Tcl_Close(interp, in);
                return TCL_ERROR;
................................................................................
    }
    Tcl_InitHashTable(&fileHash, TCL_STRING_KEYS);
    pos[0] = Tcl_Tell(out);
    if (!isList && (objc > 3)) {
        strip = Tcl_GetString(objv[3]);
        slen = strlen(strip);
    }
    for (i = 0; i < lobjc; i += (isList ? 2 : 1)) {
        const char *path, *name;

        path = Tcl_GetString(lobjv[i]);
        if (isList) {
            name = Tcl_GetString(lobjv[i + 1]);
        } else {
            name = path;
................................................................................
        if (ZipAddFile(interp, path, name, out, pw, buf, sizeof (buf),
                       &fileHash) != TCL_OK) {
            goto done;
        }
    }
    pos[1] = Tcl_Tell(out);
    count = 0;
    for (i = 0; i < lobjc; i += (isList ? 2 : 1)) {
        const char *path, *name;

        path = Tcl_GetString(lobjv[i]);
        if (isList) {
            name = Tcl_GetString(lobjv[i + 1]);
        } else {
            name = path;
................................................................................
        zip_write_short(buf + ZIP_CENTRAL_FCOMMENTLEN_OFFS, 0);
        zip_write_short(buf + ZIP_CENTRAL_DISKFILE_OFFS, 0);
        zip_write_short(buf + ZIP_CENTRAL_IATTR_OFFS, 0);
        zip_write_int(buf + ZIP_CENTRAL_EATTR_OFFS, 0);
        zip_write_int(buf + ZIP_CENTRAL_LOCALHDR_OFFS, z->offset - pos[0]);
        if (
            (Tcl_Write(out, buf, ZIP_CENTRAL_HEADER_LEN) != ZIP_CENTRAL_HEADER_LEN)
            || (Tcl_Write(out, z->name, len) != len)
        ) {
            Tcl_SetObjResult(interp, Tcl_NewStringObj("write error", -1));
            goto done;
        }
        count++;
    }
    Tcl_Flush(out);
................................................................................
        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;
}
 
/*
 *-------------------------------------------------------------------------
 *
 * ZipFSExistsObjCmd --
 *
 *      This procedure is invoked to process the "zipfs::exists" command.
 *    It tests for the existence of a file in the ZIP filesystem and
................................................................................
    ReadLock();
    z = ZipFSLookup(filename);
    if (z != NULL) {
        Tcl_Obj *result = Tcl_GetObjResult(interp);

        Tcl_ListObjAppendElement(interp, result,
                     Tcl_NewStringObj(z->zipfile->name, -1));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(z->nbyte));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(z->nbytecompr));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(z->offset));
    }
    Unlock();
    return TCL_OK;
}
 
/*
 *-------------------------------------------------------------------------
................................................................................
            }
            Tcl_Free((char *) info);
            ZIPFS_ERROR(interp,"decompression error");
            goto error;
        }
    }
wrapchan:
    sprintf(cname, "zipfs_%lx_%d", (unsigned long) z->offset, ZipFS.idCount++);
    z->zipfile->nopen++;
    Unlock();
    return Tcl_CreateChannel(&ZipChannelType, cname, (ClientData) info, flags);

error:
    Unlock();
    return NULL;
................................................................................
    if (z == NULL) {
        ZIPFS_ERROR(interp,"file not found");
        ret = TCL_ERROR;
        goto done;
    }
    switch (index) {
        case 0:
        *objPtrRef = Tcl_NewIntObj(z->nbyte);
        goto done;
        case 1:
        *objPtrRef= Tcl_NewIntObj(z->nbytecompr);
        goto done;
        case 2:
        *objPtrRef= Tcl_NewLongObj(z->offset);
        goto done;
        case 3:
        *objPtrRef= Tcl_NewStringObj(z->zipfile->mntpt, z->zipfile->mntptlen);
        goto done;
        case 4:
        *objPtrRef= Tcl_NewStringObj(z->zipfile->name, -1);
        goto done;
................................................................................
{
    /*
     * Tclkit_MainHook --
     * Performs the argument munging for the shell
     */
    char *archive;

    Tcl_FindExecutable(*argv[0]);
    archive=(char *)Tcl_GetNameOfExecutable();
    TclZipfs_Init(NULL);
    /*
    ** Look for init.tcl in one of the locations mounted later in this function
    */
    if(!TclZipfs_Mount(NULL, ZIPFS_APP_MOUNT, archive, NULL)) {
        int found;






|












|







 







|







 







|







 







|







 







>
|
>
|







 







|



|







 







|







 







|







 







|













|







 







|








|








>
|





|







 







|












|







 







|
>
>







 







>
|







 







|







 







|







 







|







 







|







 







|







 







|
|
|







 







|







 







|


|


|







 







|







182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
...
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
....
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
....
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
....
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
....
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
....
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
....
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
....
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
....
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
....
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
....
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
....
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
....
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
....
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
....
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
....
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
....
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
....
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
....
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
....
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
4115
4116
4117
4118
4119
4120
....
4409
4410
4411
4412
4413
4414
4415
4416
4417
4418
4419
4420
4421
4422
4423
#if defined(_WIN32) || defined(_WIN64)
    HANDLE mh;
#endif
    size_t nopen;             /* Number of open files on archive */
    struct ZipEntry *entries; /* List of files in archive */
    struct ZipEntry *topents; /* List of top-level dirs in archive */
#if HAS_DRIVES
    int mntdrv;               /* Drive letter of mount point */
#endif
    size_t mntptlen;
    char *mntpt;              /* Mount point */
} ZipFile;

/*
 * In-core description of file contained in mounted ZIP archive.
 */

typedef struct ZipEntry {
    char *name;               /* The full pathname of the virtual file */
    ZipFile *zipfile;         /* The ZIP file holding this virtual file */
    Tcl_WideInt offset;       /* Data offset into memory mapped ZIP file */
    int nbyte;                /* Uncompressed size of the virtual file */
    int nbytecompr;           /* Compressed size of the virtual file */
    int cmeth;                /* Compress method */
    int isdir;                  /* Set to 1 if directory, or -1 if root */
    int depth;                   /* Number of slashes in path. */
    int crc32;                /* CRC-32 */
    int timestamp;            /* Modification time */
................................................................................
    ZipFile *zipfile;         /* The ZIP file holding this channel */
    ZipEntry *zipentry;       /* Pointer back to virtual file */
    size_t nmax;              /* Max. size for write */
    size_t nbyte;             /* Number of bytes of uncompressed data */
    size_t nread;             /* Pos of next byte to be read from the channel */
    unsigned char *ubuf;      /* Pointer to the uncompressed data */
    int iscompr;              /* True if data is compressed */
    int isdir;                /* Set to 1 if directory, or -1 if root */
    int isenc;                /* True if data is encrypted */
    int iswr;                 /* True if open for writing */
    unsigned long keys[3];    /* Key for decryption */
} ZipChannel;

/*
 * Global variables.
................................................................................
        if (Tcl_SetChannelOption(interp, zf->chan, "-translation", "binary") != TCL_OK) {
            goto error;
        }
        if (Tcl_SetChannelOption(interp, zf->chan, "-encoding", "binary") != TCL_OK) {
            goto error;
        }
        zf->length = Tcl_Seek(zf->chan, 0, SEEK_END);
        if ((zf->length - ZIP_CENTRAL_END_LEN) > (64 * 1024 * 1024 - ZIP_CENTRAL_END_LEN)) {
            ZIPFS_ERROR(interp,"illegal file size");
            goto error;
        }
        Tcl_Seek(zf->chan, 0, SEEK_SET);
        zf->tofree = zf->data = (unsigned char *) Tcl_AttemptAlloc(zf->length);
        if (zf->tofree == NULL) {
            ZIPFS_ERROR(interp,"out of memory")
................................................................................
        if (i != zf->length) {
            ZIPFS_ERROR(interp,"file read error");
            goto error;
        }
        Tcl_Close(interp, zf->chan);
        zf->chan = NULL;
    } else {
#if defined(_WIN32) || defined(_WIN64)
#   ifdef _WIN64
        i = GetFileSizeEx((HANDLE) handle, (PLARGE_INTEGER)&zf->length);
        if (
            (i == 0) ||
#   else
        zf->length = GetFileSize((HANDLE) handle, 0);
        if (
................................................................................
    char *buf, int bufsize, Tcl_HashTable *fileHash
) {
    Tcl_Channel in;
    Tcl_HashEntry *hPtr;
    ZipEntry *z;
    z_stream stream;
    const char *zpath;
    int crc, flush, zpathlen, olen;
    size_t nbyte, nbytecompr, len, align = 0;
    Tcl_WideInt pos[3];
    int mtime = 0, isNew, cmeth;
    unsigned long keys[3], keys0[3];
    char obuf[4096];

    zpath = name;
    while (zpath != NULL && zpath[0] == '/') {
        zpath++;
    }
................................................................................
            mtime = statBuf.st_mtime;
        }
        Tcl_DecrRefCount(pathObj);
    }
    Tcl_ResetResult(interp);
    crc = 0;
    nbyte = nbytecompr = 0;
    while ((len = Tcl_Read(in, buf, bufsize)) + 1 > 1) {
        crc = crc32(crc, (unsigned char *) buf, len);
        nbyte += len;
    }
    if (len == (size_t)-1) {
        if (nbyte == 0) {
            if (strcmp("illegal operation on a directory",
                   Tcl_PosixError(interp)) == 0) {
            Tcl_Close(interp, in);
            return TCL_OK;
            }
        }
................................................................................
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    pos[0] = Tcl_Tell(out);
    memset(buf, '\0', ZIP_LOCAL_HEADER_LEN);
    memcpy(buf + ZIP_LOCAL_HEADER_LEN, zpath, zpathlen);
    len = zpathlen + ZIP_LOCAL_HEADER_LEN;
    if ((size_t)Tcl_Write(out, buf, len) != len) {
wrerr:
    Tcl_AppendResult(interp, "write error", (char *) NULL);
    Tcl_Close(interp, in);
    return TCL_ERROR;
    }
    if ((len + pos[0]) & 3) {
        unsigned char abuf[8];
................................................................................
         * Align payload to next 4-byte boundary using a dummy extra
         * entry similar to the zipalign tool from Android's SDK.
         */
        align = 4 + ((len + pos[0]) & 3);
        zip_write_short(abuf, 0xffff);
        zip_write_short(abuf + 2, align - 4);
        zip_write_int(abuf + 4, 0x03020100);
        if ((size_t)Tcl_Write(out, (const char *)abuf, align) != align) {
            goto wrerr;
        }
    }
    if (passwd != NULL) {
        int i, ch, tmp;
        unsigned char kvbuf[24];
        Tcl_Obj *ret;
................................................................................
        Tcl_AppendResult(interp, "compression init error on \"", path, "\"",
                 (char *) NULL);
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    do {
    len = Tcl_Read(in, buf, bufsize);
    if (len == (size_t)-1) {
        Tcl_AppendResult(interp, "read error on \"", path, "\"",
                 (char *) NULL);
        deflateEnd(&stream);
        Tcl_Close(interp, in);
        return TCL_ERROR;
    }
    stream.avail_in = len;
    stream.next_in = (unsigned char *) buf;
    flush = Tcl_Eof(in) ? Z_FINISH : Z_NO_FLUSH;
    do {
        stream.avail_out = sizeof (obuf);
        stream.next_out = (unsigned char *) obuf;
        len = deflate(&stream, flush);
        if (len == (size_t)Z_STREAM_ERROR) {
            Tcl_AppendResult(interp, "deflate error on \"", path, "\"",
                     (char *) NULL);
            deflateEnd(&stream);
            Tcl_Close(interp, in);
            return TCL_ERROR;
        }
        olen = sizeof (obuf) - stream.avail_out;
................................................................................
        /*
         * Compressed file larger than input,
         * write it again uncompressed.
         */
        if (Tcl_Seek(in, 0, SEEK_SET) != 0) {
            goto seekErr;
        }
        if (Tcl_Seek(out, pos[2], SEEK_SET) != pos[2]) {
seekErr:
            Tcl_Close(interp, in);
            Tcl_AppendResult(interp, "seek error", (char *) NULL);
            return TCL_ERROR;
        }
        nbytecompr = (passwd != NULL) ? 12 : 0;
        while (1) {
            len = Tcl_Read(in, buf, bufsize);
            if (len == (size_t)-1) {
            Tcl_AppendResult(interp, "read error on \"", path, "\"",
                     (char *) NULL);
            Tcl_Close(interp, in);
            return TCL_ERROR;
            } else if (len == 0) {
            break;
            }
            if (passwd != NULL) {
            size_t i;
            int tmp;

            for (i = 0; i < len; i++) {
                buf[i] = (char) zencode(keys0, crc32tab, buf[i], tmp);
            }
            }
            if ((size_t)Tcl_Write(out, buf, len) != len) {
            Tcl_AppendResult(interp, "write error", (char *) NULL);
            Tcl_Close(interp, in);
            return TCL_ERROR;
            }
            nbytecompr += len;
        }
        cmeth = ZIP_COMPMETH_STORED;
................................................................................
    zip_write_short(buf + ZIP_LOCAL_MTIME_OFFS, ToDosTime(z->timestamp));
    zip_write_short(buf + ZIP_LOCAL_MDATE_OFFS, ToDosDate(z->timestamp));
    zip_write_int(buf + ZIP_LOCAL_CRC32_OFFS, z->crc32);
    zip_write_int(buf + ZIP_LOCAL_COMPLEN_OFFS, z->nbytecompr);
    zip_write_int(buf + ZIP_LOCAL_UNCOMPLEN_OFFS, z->nbyte);
    zip_write_short(buf + ZIP_LOCAL_PATHLEN_OFFS, zpathlen);
    zip_write_short(buf + ZIP_LOCAL_EXTRALEN_OFFS, align);
    if (Tcl_Seek(out, pos[0], SEEK_SET) != pos[0]) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "seek error", (char *) NULL);
        return TCL_ERROR;
    }
    if (Tcl_Write(out, buf, ZIP_LOCAL_HEADER_LEN) != ZIP_LOCAL_HEADER_LEN) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "write error", (char *) NULL);
        return TCL_ERROR;
    }
    Tcl_Flush(out);
    if (Tcl_Seek(out, pos[1], SEEK_SET) != pos[1]) {
        Tcl_DeleteHashEntry(hPtr);
        Tcl_Free((char *) z);
        Tcl_AppendResult(interp, "seek error", (char *) NULL);
        return TCL_ERROR;
    }
    return TCL_OK;
}
................................................................................
 */

static int
ZipFSMkZipOrImgObjCmd(ClientData clientData, Tcl_Interp *interp,
                      int isImg, int isList, int objc, Tcl_Obj *const objv[])
{
    Tcl_Channel out;
    int pwlen = 0, count, ret = TCL_ERROR, lobjc;
    size_t len, slen = 0, i = 0;
    Tcl_WideInt pos[3];
    Tcl_Obj **lobjv, *list = NULL;
    ZipEntry *z;
    Tcl_HashEntry *hPtr;
    Tcl_HashSearch search;
    Tcl_HashTable fileHash;
    char *strip = NULL, *pw = NULL, pwbuf[264], buf[4096];

................................................................................
                ZipFSCloseArchive(interp, zf);
            } else {
                WriteLock();
                zf->nopen--;
                Unlock();
            }
        } else {
            size_t k;
            int m, n;
            Tcl_Channel in;
            const char *errMsg = "seek error";

            /*
             * Fall back to read it as plain file which
             * hopefully is a static tclsh or wish binary
             * with proper zipfs infrastructure built in.
................................................................................
                Tcl_DecrRefCount(list);
                Tcl_Close(interp, out);
                return TCL_ERROR;
            }
            Tcl_SetChannelOption(interp, in, "-translation", "binary");
            Tcl_SetChannelOption(interp, in, "-encoding", "binary");
            i = Tcl_Seek(in, 0, SEEK_END);
            if (i == (size_t)-1) {
cperr:
                memset(pwbuf, 0, sizeof (pwbuf));
                Tcl_DecrRefCount(list);
                Tcl_SetObjResult(interp, Tcl_NewStringObj(errMsg, -1));
                Tcl_Close(interp, out);
                Tcl_Close(interp, in);
                return TCL_ERROR;
................................................................................
    }
    Tcl_InitHashTable(&fileHash, TCL_STRING_KEYS);
    pos[0] = Tcl_Tell(out);
    if (!isList && (objc > 3)) {
        strip = Tcl_GetString(objv[3]);
        slen = strlen(strip);
    }
    for (i = 0; i < (size_t)lobjc; i += (isList ? 2 : 1)) {
        const char *path, *name;

        path = Tcl_GetString(lobjv[i]);
        if (isList) {
            name = Tcl_GetString(lobjv[i + 1]);
        } else {
            name = path;
................................................................................
        if (ZipAddFile(interp, path, name, out, pw, buf, sizeof (buf),
                       &fileHash) != TCL_OK) {
            goto done;
        }
    }
    pos[1] = Tcl_Tell(out);
    count = 0;
    for (i = 0; i < (size_t)lobjc; i += (isList ? 2 : 1)) {
        const char *path, *name;

        path = Tcl_GetString(lobjv[i]);
        if (isList) {
            name = Tcl_GetString(lobjv[i + 1]);
        } else {
            name = path;
................................................................................
        zip_write_short(buf + ZIP_CENTRAL_FCOMMENTLEN_OFFS, 0);
        zip_write_short(buf + ZIP_CENTRAL_DISKFILE_OFFS, 0);
        zip_write_short(buf + ZIP_CENTRAL_IATTR_OFFS, 0);
        zip_write_int(buf + ZIP_CENTRAL_EATTR_OFFS, 0);
        zip_write_int(buf + ZIP_CENTRAL_LOCALHDR_OFFS, z->offset - pos[0]);
        if (
            (Tcl_Write(out, buf, ZIP_CENTRAL_HEADER_LEN) != ZIP_CENTRAL_HEADER_LEN)
            || ((size_t)Tcl_Write(out, z->name, len) != len)
        ) {
            Tcl_SetObjResult(interp, Tcl_NewStringObj("write error", -1));
            goto done;
        }
        count++;
    }
    Tcl_Flush(out);
................................................................................
        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;
}

/*
 *-------------------------------------------------------------------------
 *
 * ZipFSExistsObjCmd --
 *
 *      This procedure is invoked to process the "zipfs::exists" command.
 *    It tests for the existence of a file in the ZIP filesystem and
................................................................................
    ReadLock();
    z = ZipFSLookup(filename);
    if (z != NULL) {
        Tcl_Obj *result = Tcl_GetObjResult(interp);

        Tcl_ListObjAppendElement(interp, result,
                     Tcl_NewStringObj(z->zipfile->name, -1));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(z->nbyte));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(z->nbytecompr));
        Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(z->offset));
    }
    Unlock();
    return TCL_OK;
}
 
/*
 *-------------------------------------------------------------------------
................................................................................
            }
            Tcl_Free((char *) info);
            ZIPFS_ERROR(interp,"decompression error");
            goto error;
        }
    }
wrapchan:
    sprintf(cname, "zipfs_%" TCL_LL_MODIFIER "x_%d", z->offset, ZipFS.idCount++);
    z->zipfile->nopen++;
    Unlock();
    return Tcl_CreateChannel(&ZipChannelType, cname, (ClientData) info, flags);

error:
    Unlock();
    return NULL;
................................................................................
    if (z == NULL) {
        ZIPFS_ERROR(interp,"file not found");
        ret = TCL_ERROR;
        goto done;
    }
    switch (index) {
        case 0:
        *objPtrRef = Tcl_NewWideIntObj(z->nbyte);
        goto done;
        case 1:
        *objPtrRef = Tcl_NewWideIntObj(z->nbytecompr);
        goto done;
        case 2:
        *objPtrRef= Tcl_NewWideIntObj(z->offset);
        goto done;
        case 3:
        *objPtrRef= Tcl_NewStringObj(z->zipfile->mntpt, z->zipfile->mntptlen);
        goto done;
        case 4:
        *objPtrRef= Tcl_NewStringObj(z->zipfile->name, -1);
        goto done;
................................................................................
{
    /*
     * Tclkit_MainHook --
     * Performs the argument munging for the shell
     */
    char *archive;

    Tcl_FindExecutable((*argv)[0]);
    archive=(char *)Tcl_GetNameOfExecutable();
    TclZipfs_Init(NULL);
    /*
    ** Look for init.tcl in one of the locations mounted later in this function
    */
    if(!TclZipfs_Mount(NULL, ZIPFS_APP_MOUNT, archive, NULL)) {
        int found;