Subversion Repositories SvarDOS

Rev

Rev 257 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 257 Rev 268
1
/*
1
/*
2
 * This file is part of the FDNPKG project
2
 * This file is part of pkg (SvarDOS)
3
 * http://fdnpkg.sourceforge.net
-
 
4
 *
-
 
5
 * Copyright (C) 2012-2016 Mateusz Viste. All rights reserved.
3
 * Copyright (C) 2012-2021 Mateusz Viste.
6
 *
4
 *
7
 * Simple library providing functions to unzip files from zip archives.
5
 * Simple library providing functions to unzip files from zip archives.
8
 */
6
 */
9
 
7
 
10
#include <stdio.h>     /* printf(), FILE, fclose()... */
8
#include <stdio.h>     /* printf(), FILE, fclose()... */
11
#include <stdlib.h>    /* NULL */
9
#include <stdlib.h>    /* NULL */
12
#include <string.h>    /* memset() */
10
#include <string.h>    /* memset() */
13
#include <time.h>      /* mktime() */
11
#include <time.h>      /* mktime() */
14
#include <utime.h>     /* utime() */
12
#include <utime.h>     /* utime() */
15
#include <unistd.h>   /* unlink() */
13
#include <unistd.h>   /* unlink() */
16
 
14
 
17
#include "crc32.h"
15
#include "crc32.h"
18
#include "kprintf.h"
16
#include "kprintf.h"
19
#include "inf.h"   /* DEFLATE support */
17
#include "inf.h"   /* INFLATE support */
20
 
18
 
21
#include "libunzip.h"  /* include self for control */
19
#include "libunzip.h"  /* include self for control */
22
 
20
 
23
 
21
 
24
/* converts a "DOS format" timestamp into unix timestamp. The DOS timestamp is constructed an array of 4 bytes, that contains following data at the bit level:
22
/* converts a "DOS format" timestamp into unix timestamp. The DOS timestamp is constructed an array of 4 bytes, that contains following data at the bit level:
25
 * HHHHHMMM MMMSSSSS YYYYYYYM MMMDDDDD
23
 * HHHHHMMM MMMSSSSS YYYYYYYM MMMDDDDD
26
 *  where:
24
 *  where:
27
 * day of month is always within 1-31 range;
25
 * day of month is always within 1-31 range;
28
 * month is always within 1-12 range;
26
 * month is always within 1-12 range;
29
 * year starts from 1980 and continues for 127 years
27
 * year starts from 1980 and continues for 127 years
30
 * seconds are actually not 0-59 but rather 0-29 as there are only 32 possible values – to get actual seconds multiply this field by 2;
28
 * seconds are actually not 0-59 but rather 0-29 as there are only 32 possible values – to get actual seconds multiply this field by 2;
31
 * minutes are always within 0-59 range;
29
 * minutes are always within 0-59 range;
32
 * hours are always within 0-23 range.     */
30
 * hours are always within 0-23 range.     */
33
static time_t dostime2unix(unsigned char *buff) {
31
static time_t dostime2unix(const unsigned char *buff) {
34
  struct tm curtime;
32
  struct tm curtime;
35
  time_t result;
33
  time_t result;
36
  memset(&curtime, 0, sizeof(curtime)); /* make sure to set everything in curtime to 0's */
34
  memset(&curtime, 0, sizeof(curtime)); /* make sure to set everything in curtime to 0's */
37
  curtime.tm_sec = (buff[0] & 31) << 1; /* seconds (0..60) */
35
  curtime.tm_sec = (buff[0] & 31) << 1; /* seconds (0..60) */
38
  curtime.tm_min = (((buff[1] << 8) | buff[0]) >> 5) & 63 ; /* minutes after the hour (0..59) */
36
  curtime.tm_min = (((buff[1] << 8) | buff[0]) >> 5) & 63 ; /* minutes after the hour (0..59) */
39
  curtime.tm_hour = (buff[1] >> 3); /* hours since midnight (0..23) */
37
  curtime.tm_hour = (buff[1] >> 3); /* hours since midnight (0..23) */
40
  curtime.tm_mday = buff[2] & 31; /* day of the month (1..31) */
38
  curtime.tm_mday = buff[2] & 31; /* day of the month (1..31) */
41
  curtime.tm_mon = ((((buff[3] << 8) | buff[2]) >> 5) & 15) - 1; /* months since January (0, 11) */
39
  curtime.tm_mon = ((((buff[3] << 8) | buff[2]) >> 5) & 15) - 1; /* months since January (0, 11) */
42
  curtime.tm_year = (buff[3] >> 1) + 80; /* years since 1900 */
40
  curtime.tm_year = (buff[3] >> 1) + 80; /* years since 1900 */
43
  curtime.tm_wday = 0; /* days since Sunday (0..6) - leave 0, mktime() will set it */
41
  curtime.tm_wday = 0; /* days since Sunday (0..6) - leave 0, mktime() will set it */
44
  curtime.tm_yday = 0; /* days since January 1 (0..365]) - leave 0, mktime() will set it */
42
  curtime.tm_yday = 0; /* days since January 1 (0..365]) - leave 0, mktime() will set it */
45
  curtime.tm_isdst = -1; /* Daylight Saving Time flag. Positive if DST is in effect, zero if not and negative if no information is available */
43
  curtime.tm_isdst = -1; /* Daylight Saving Time flag. Positive if DST is in effect, zero if not and negative if no information is available */
46
  result = mktime(&curtime);
44
  result = mktime(&curtime);
47
  if (result == (time_t)-1) return(0);
45
  if (result == (time_t)-1) return(0);
48
  return(result);
46
  return(result);
49
}
47
}
50
 
48
 
51
 
49
 
52
/* opens a zip file and provides the list of files in the archive.
50
/* opens a zip file and provides the list of files in the archive.
53
   returns a pointer to a ziplist (linked list) with all records, or NULL on error.
51
   returns a pointer to a ziplist (linked list) with all records, or NULL on error.
54
   The ziplist is allocated automatically, and must be freed via zip_freelist. */
52
   The ziplist is allocated automatically, and must be freed via zip_freelist. */
55
struct ziplist *zip_listfiles(FILE *fd) {
53
struct ziplist *zip_listfiles(FILE *fd) {
56
  struct ziplist *reslist = NULL;
54
  struct ziplist *reslist = NULL;
57
  struct ziplist *newentry;
55
  struct ziplist *newentry;
58
  unsigned long entrysig;
56
  unsigned long entrysig;
59
  unsigned short filenamelen, extrafieldlen, filecommentlen;
57
  unsigned short filenamelen, extrafieldlen, filecommentlen;
60
  unsigned long compfilelen;
58
  unsigned long compfilelen;
61
  int centraldirectoryfound = 0;
59
  int centraldirectoryfound = 0;
62
  unsigned int ux;
60
  unsigned int ux;
63
  unsigned char hdrbuff[64];
61
  unsigned char hdrbuff[64];
64
 
62
 
65
  rewind(fd);  /* make sure the file cursor is at the very beginning of the file */
63
  rewind(fd);  /* make sure the file cursor is at the very beginning of the file */
66
 
64
 
67
  for (;;) { /* read entry after entry */
65
  for (;;) { /* read entry after entry */
68
    int x, eofflag;
66
    int x, eofflag;
69
    long longbuff;
67
    long longbuff;
70
    entrysig = 0;
68
    entrysig = 0;
71
    eofflag = 0;
69
    eofflag = 0;
72
    /* read the entry signature first */
70
    /* read the entry signature first */
73
    for (x = 0; x < 32; x += 8) {
71
    for (x = 0; x < 32; x += 8) {
74
      if ((longbuff = fgetc(fd)) == EOF) {
72
      if ((longbuff = fgetc(fd)) == EOF) {
75
        eofflag = 1;
73
        eofflag = 1;
76
        break;
74
        break;
77
      }
75
      }
78
      entrysig |= (longbuff << x);
76
      entrysig |= (longbuff << x);
79
    }
77
    }
80
    if (eofflag != 0) break;
78
    if (eofflag != 0) break;
81
    /* printf("sig: 0x%08x\n", entrysig); */
79
    /* printf("sig: 0x%08x\n", entrysig); */
82
    if (entrysig == 0x04034b50ul) { /* local file */
80
    if (entrysig == 0x04034b50ul) { /* local file */
83
      unsigned int generalpurposeflags;
81
      unsigned int generalpurposeflags;
84
      /* read and parse the zip header */
82
      /* read and parse the zip header */
85
      fread(hdrbuff, 1, 26, fd);
83
      fread(hdrbuff, 1, 26, fd);
86
      /* read filename's length so I can allocate the proper amound of mem */
84
      /* read filename's length so I can allocate the proper amound of mem */
87
      filenamelen = hdrbuff[23];
85
      filenamelen = hdrbuff[23];
88
      filenamelen <<= 8;
86
      filenamelen <<= 8;
89
      filenamelen |= hdrbuff[22];
87
      filenamelen |= hdrbuff[22];
90
      /* create new entry and link it into the list */
88
      /* create new entry and link it into the list */
91
      newentry = calloc(sizeof(struct ziplist) + filenamelen, 1);
89
      newentry = calloc(sizeof(struct ziplist) + filenamelen, 1);
92
      if (newentry == NULL) {
90
      if (newentry == NULL) {
93
        kitten_puts(8, 0, "Out of memory!");
91
        kitten_puts(8, 0, "Out of memory!");
94
        zip_freelist(&reslist);
92
        zip_freelist(&reslist);
95
        break;
93
        break;
96
      }
94
      }
97
      newentry->nextfile = reslist;
95
      newentry->nextfile = reslist;
98
      newentry->flags = 0;
96
      newentry->flags = 0;
99
      reslist = newentry;
97
      reslist = newentry;
100
      /* read further areas of the header, and fill zip entry */
98
      /* read further areas of the header, and fill zip entry */
101
      generalpurposeflags = hdrbuff[3];  /* parse the general */
99
      generalpurposeflags = hdrbuff[3];  /* parse the general */
102
      generalpurposeflags <<= 8;         /* purpose flags and */
100
      generalpurposeflags <<= 8;         /* purpose flags and */
103
      generalpurposeflags |= hdrbuff[2]; /* save them for later */
101
      generalpurposeflags |= hdrbuff[2]; /* save them for later */
104
      newentry->compmethod = hdrbuff[4] | (hdrbuff[5] << 8);
102
      newentry->compmethod = hdrbuff[4] | (hdrbuff[5] << 8);
105
      newentry->timestamp = dostime2unix(&hdrbuff[6]);
103
      newentry->timestamp = dostime2unix(&hdrbuff[6]);
106
      newentry->crc32 = 0;
104
      newentry->crc32 = 0;
107
      for (x = 13; x >= 10; x--) {
105
      for (x = 13; x >= 10; x--) {
108
        newentry->crc32 <<= 8;
106
        newentry->crc32 <<= 8;
109
        newentry->crc32 |= hdrbuff[x];
107
        newentry->crc32 |= hdrbuff[x];
110
      }
108
      }
111
      newentry->compressedfilelen = 0;
109
      newentry->compressedfilelen = 0;
112
      for (x = 17; x >= 14; x--) {
110
      for (x = 17; x >= 14; x--) {
113
        newentry->compressedfilelen <<= 8;
111
        newentry->compressedfilelen <<= 8;
114
        newentry->compressedfilelen |= hdrbuff[x];
112
        newentry->compressedfilelen |= hdrbuff[x];
115
      }
113
      }
116
      newentry->filelen = 0;
114
      newentry->filelen = 0;
117
      for (x = 21; x >= 18; x--) {
115
      for (x = 21; x >= 18; x--) {
118
        newentry->filelen <<= 8;
116
        newentry->filelen <<= 8;
119
        newentry->filelen |= hdrbuff[x];
117
        newentry->filelen |= hdrbuff[x];
120
      }
118
      }
121
      extrafieldlen = hdrbuff[25];
119
      extrafieldlen = hdrbuff[25];
122
      extrafieldlen <<= 8;
120
      extrafieldlen <<= 8;
123
      extrafieldlen |= hdrbuff[24];
121
      extrafieldlen |= hdrbuff[24];
124
      /* printf("Filename len: %d / extrafield len: %d / compfile len: %ld / filelen: %ld\n", filenamelen, extrafieldlen, newentry->compressedfilelen, newentry->filelen); */
122
      /* printf("Filename len: %d / extrafield len: %d / compfile len: %ld / filelen: %ld\n", filenamelen, extrafieldlen, newentry->compressedfilelen, newentry->filelen); */
125
      /* check general purpose flags */
123
      /* check general purpose flags */
126
      if ((generalpurposeflags & 1) != 0) newentry->flags |= ZIP_FLAG_ENCRYPTED;
124
      if ((generalpurposeflags & 1) != 0) newentry->flags |= ZIP_FLAG_ENCRYPTED;
127
      /* parse the filename */
125
      /* parse the filename */
128
      for (ux = 0; ux < filenamelen; ux++) newentry->filename[ux] = fgetc(fd); /* store filename */
126
      for (ux = 0; ux < filenamelen; ux++) newentry->filename[ux] = fgetc(fd); /* store filename */
129
      if (newentry->filename[filenamelen - 1] == '/') newentry->flags |= ZIP_FLAG_ISADIR; /* if filename ends with / it's a dir. Note that ZIP forbids the usage of '\' in ZIP paths anyway */
127
      if (newentry->filename[filenamelen - 1] == '/') newentry->flags |= ZIP_FLAG_ISADIR; /* if filename ends with / it's a dir. Note that ZIP forbids the usage of '\' in ZIP paths anyway */
130
      /* printf("Filename: %s (%ld bytes compressed)\n", newentry->filename, newentry->compressedfilelen); */
128
      /* printf("Filename: %s (%ld bytes compressed)\n", newentry->filename, newentry->compressedfilelen); */
131
      newentry->dataoffset = ftell(fd) + extrafieldlen;
129
      newentry->dataoffset = ftell(fd) + extrafieldlen;
132
      /* skip rest of fields and data */
130
      /* skip rest of fields and data */
133
      fseek(fd, (extrafieldlen + newentry->compressedfilelen), SEEK_CUR);
131
      fseek(fd, (extrafieldlen + newentry->compressedfilelen), SEEK_CUR);
134
    } else if (entrysig == 0x02014b50ul) { /* central directory */
132
    } else if (entrysig == 0x02014b50ul) { /* central directory */
135
      centraldirectoryfound = 1;
133
      centraldirectoryfound = 1;
136
      /* parse header now */
134
      /* parse header now */
137
      fread(hdrbuff, 1, 42, fd);
135
      fread(hdrbuff, 1, 42, fd);
138
      filenamelen = hdrbuff[22] | (hdrbuff[23] << 8);
136
      filenamelen = hdrbuff[22] | (hdrbuff[23] << 8);
139
      extrafieldlen = hdrbuff[24] | (hdrbuff[25] << 8);
137
      extrafieldlen = hdrbuff[24] | (hdrbuff[25] << 8);
140
      filecommentlen = hdrbuff[26] | (hdrbuff[27] << 8);
138
      filecommentlen = hdrbuff[26] | (hdrbuff[27] << 8);
141
      compfilelen = 0;
139
      compfilelen = 0;
142
      for (x = 17; x >= 14; x--) {
140
      for (x = 17; x >= 14; x--) {
143
        compfilelen <<= 8;
141
        compfilelen <<= 8;
144
        compfilelen |= hdrbuff[x];
142
        compfilelen |= hdrbuff[x];
145
      }
143
      }
146
      /* printf("central dir\n"); */
144
      /* printf("central dir\n"); */
147
      /* skip rest of fields and data */
145
      /* skip rest of fields and data */
148
      fseek(fd, (filenamelen + extrafieldlen + compfilelen + filecommentlen), SEEK_CUR);
146
      fseek(fd, (filenamelen + extrafieldlen + compfilelen + filecommentlen), SEEK_CUR);
149
    } else if (entrysig == 0x08074b50ul) { /* Data descriptor header */
147
    } else if (entrysig == 0x08074b50ul) { /* Data descriptor header */
150
      /* no need to read the header we just have to skip it */
148
      /* no need to read the header we just have to skip it */
151
      fseek(fd, 12, SEEK_CUR); /* the header is 3x4 bytes (CRC + compressed len + uncompressed len) */
149
      fseek(fd, 12, SEEK_CUR); /* the header is 3x4 bytes (CRC + compressed len + uncompressed len) */
152
    } else { /* unknown sig */
150
    } else { /* unknown sig */
153
      kitten_printf(8, 1, "unknown zip sig: 0x%08lx", entrysig);
151
      kitten_printf(8, 1, "unknown zip sig: 0x%08lx", entrysig);
154
      puts("");
152
      puts("");
155
      zip_freelist(&reslist);
153
      zip_freelist(&reslist);
156
      break;
154
      break;
157
    }
155
    }
158
  }
156
  }
159
  /* if we got no central directory record, the file is incomplete */
157
  /* if we got no central directory record, the file is incomplete */
160
  if (centraldirectoryfound == 0) zip_freelist(&reslist);
158
  if (centraldirectoryfound == 0) zip_freelist(&reslist);
161
  return(reslist);
159
  return(reslist);
162
}
160
}
163
 
161
 
164
 
162
 
165
 
163
 
166
/* unzips a file. zipfd points to the open zip file, curzipnode to the entry to extract, and fulldestfilename is the destination file where to unzip it. returns 0 on success, non-zero otherwise. */
164
/* unzips a file. zipfd points to the open zip file, curzipnode to the entry to extract, and fulldestfilename is the destination file where to unzip it. returns 0 on success, non-zero otherwise. */
167
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, char *fulldestfilename) {
165
int zip_unzip(FILE *zipfd, struct ziplist *curzipnode, const char *fulldestfilename) {
168
  #define buffsize 32 * 1024l /* MUST be at least 32K */
166
  #define buffsize 32 * 1024l /* MUST be at least 32K */
169
  FILE *filefd;
167
  FILE *filefd;
170
  unsigned long cksum;
168
  unsigned long cksum;
171
  int extract_res;
169
  int extract_res;
172
  unsigned char *buff;
170
  unsigned char *buff;
173
  struct utimbuf filetimestamp;
171
  struct utimbuf filetimestamp;
174
 
172
 
175
  /* first of all, check we support the compression method */
173
  /* first of all, check we support the compression method */
176
  switch (curzipnode->compmethod) {
174
  switch (curzipnode->compmethod) {
177
    case 0:  /* stored */
175
    case 0:  /* stored */
178
    case 8:  /* deflated */
176
    case 8:  /* deflated */
179
      break;
177
      break;
180
    default: /* unsupported compression method, sorry */
178
    default: /* unsupported compression method, sorry */
181
      return(-1);
179
      return(-1);
182
      break;
180
      break;
183
  }
181
  }
184
 
182
 
185
  /* open the dst file */
183
  /* open the dst file */
186
  filefd = fopen(fulldestfilename, "wb");
184
  filefd = fopen(fulldestfilename, "wb");
187
  if (filefd == NULL) return(-2);  /* failed to open the dst file */
185
  if (filefd == NULL) return(-2);  /* failed to open the dst file */
188
 
186
 
189
  /* allocate buffers for data I/O */
187
  /* allocate buffers for data I/O */
190
  buff = malloc(buffsize);
188
  buff = malloc(buffsize);
191
  if (buff == NULL) {
189
  if (buff == NULL) {
192
    fclose(filefd);
190
    fclose(filefd);
193
    unlink(fulldestfilename); /* remove the failed file once it is closed */
191
    unlink(fulldestfilename); /* remove the failed file once it is closed */
194
    return(-6);
192
    return(-6);
195
  }
193
  }
196
 
194
 
197
  if (fseek(zipfd, curzipnode->dataoffset, SEEK_SET) != 0) { /* set the reading position inside the zip file */
195
  if (fseek(zipfd, curzipnode->dataoffset, SEEK_SET) != 0) { /* set the reading position inside the zip file */
198
    free(buff);
196
    free(buff);
199
    fclose(filefd);
197
    fclose(filefd);
200
    unlink(fulldestfilename); /* remove the failed file once it is closed */
198
    unlink(fulldestfilename); /* remove the failed file once it is closed */
201
    return(-7);
199
    return(-7);
202
  }
200
  }
203
  extract_res = -255;
201
  extract_res = -255;
204
 
202
 
205
  cksum = crc32_init(); /* init the crc32 */
203
  cksum = crc32_init(); /* init the crc32 */
206
 
204
 
207
  if (curzipnode->compmethod == 0) { /* if the file is stored, copy it over */
205
  if (curzipnode->compmethod == 0) { /* if the file is stored, copy it over */
208
    long i, toread;
206
    long i, toread;
209
    extract_res = 0;   /* assume we will succeed */
207
    extract_res = 0;   /* assume we will succeed */
210
    for (i = 0; i < curzipnode->filelen;) {
208
    for (i = 0; i < curzipnode->filelen;) {
211
      toread = curzipnode->filelen - i;
209
      toread = curzipnode->filelen - i;
212
      if (toread > buffsize) toread = buffsize;
210
      if (toread > buffsize) toread = buffsize;
213
      if (fread(buff, toread, 1, zipfd) != 1) extract_res = -3;   /* read a chunk of data */
211
      if (fread(buff, toread, 1, zipfd) != 1) extract_res = -3;   /* read a chunk of data */
214
      crc32_feed(&cksum, buff, toread); /* update the crc32 checksum */
212
      crc32_feed(&cksum, buff, toread); /* update the crc32 checksum */
215
      if (fwrite(buff, toread, 1, filefd) != 1) extract_res = -4; /* write data chunk to dst file */
213
      if (fwrite(buff, toread, 1, filefd) != 1) extract_res = -4; /* write data chunk to dst file */
216
      i += toread;
214
      i += toread;
217
    }
215
    }
218
  } else if (curzipnode->compmethod == 8) {  /* if the file is deflated, inflate it */
216
  } else if (curzipnode->compmethod == 8) {  /* if the file is deflated, inflate it */
219
    extract_res = inf(zipfd, filefd, buff, &cksum, curzipnode->compressedfilelen);
217
    extract_res = inf(zipfd, filefd, buff, &cksum, curzipnode->compressedfilelen);
220
  }
218
  }
221
 
219
 
222
  /* clean up memory, close the dst file and terminates crc32 */
220
  /* clean up memory, close the dst file and terminates crc32 */
223
  free(buff);
221
  free(buff);
224
  fclose(filefd);   /* close the dst file */
222
  fclose(filefd);   /* close the dst file */
225
  crc32_finish(&cksum);
223
  crc32_finish(&cksum);
226
 
224
 
227
  /* printf("extract_res=%d / cksum_expected=%08lX / cksum_obtained=%08lX\n", extract_res, curzipnode->crc32, cksum); */
225
  /* printf("extract_res=%d / cksum_expected=%08lX / cksum_obtained=%08lX\n", extract_res, curzipnode->crc32, cksum); */
228
  if (extract_res != 0) {  /* was the extraction process successful? */
226
  if (extract_res != 0) {  /* was the extraction process successful? */
229
    unlink(fulldestfilename); /* remove the failed file */
227
    unlink(fulldestfilename); /* remove the failed file */
230
    return(extract_res);
228
    return(extract_res);
231
  }
229
  }
232
  if (cksum != curzipnode->crc32) { /* is the crc32 ok after extraction? */
230
  if (cksum != curzipnode->crc32) { /* is the crc32 ok after extraction? */
233
    unlink(fulldestfilename); /* remove the failed file */
231
    unlink(fulldestfilename); /* remove the failed file */
234
    return(-9);
232
    return(-9);
235
  }
233
  }
236
  /* Set the timestamp of the new file to what was set in the zip file */
234
  /* Set the timestamp of the new file to what was set in the zip file */
237
  filetimestamp.actime  = curzipnode->timestamp;
235
  filetimestamp.actime  = curzipnode->timestamp;
238
  filetimestamp.modtime = curzipnode->timestamp;
236
  filetimestamp.modtime = curzipnode->timestamp;
239
  utime(fulldestfilename, &filetimestamp);
237
  utime(fulldestfilename, &filetimestamp);
240
  return(0);
238
  return(0);
241
}
239
}
242
 
240
 
243
 
241
 
244
 
242
 
245
/* Call this to free a ziplist computed by zip_listfiles() */
243
/* Call this to free a ziplist computed by zip_listfiles() */
246
void zip_freelist(struct ziplist **ziplist) {
244
void zip_freelist(struct ziplist **ziplist) {
247
  struct ziplist *zipentrytobefreed;
245
  struct ziplist *zipentrytobefreed;
248
  while (*ziplist != NULL) { /* iterate through the linked list and free all nodes */
246
  while (*ziplist != NULL) { /* iterate through the linked list and free all nodes */
249
    zipentrytobefreed = *ziplist;
247
    zipentrytobefreed = *ziplist;
250
    *ziplist = zipentrytobefreed->nextfile;
248
    *ziplist = zipentrytobefreed->nextfile;
251
    /* free the node entry */
249
    /* free the node entry */
252
    free(zipentrytobefreed);
250
    free(zipentrytobefreed);
253
  }
251
  }
254
  *ziplist = NULL;
252
  *ziplist = NULL;
255
}
253
}
256
 
254