Fossil

Check-in [90048e0b]
Login

Check-in [90048e0b]

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

Overview
Comment:Add an "extended timestamp" field to generated ZIP archives. The extended timestamp is in UTC so it does not mangle the time when the server and client are in different timezones. Ticket [28044ab5a42b75]
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 90048e0b30f12377b33110b279f19299643fe830
User & Date: drh 2009-08-15 02:17:27
References
2009-08-15
12:05 Ticket [8d6efe4f] fossil version [90048e0b30] will not save zip archive on winXP status still Open with 2 other changes ... (artifact: 9dda1213 user: drh)
05:59 New ticket [8d6efe4f]. ... (artifact: 9cf3e281 user: anonymous)
02:18 Fixed ticket [28044ab5]: Zip archive dates are in the future plus 2 other changes ... (artifact: bb1e3440 user: drh)
Context
2009-08-15
08:17
Update documentation of 'proxy' configuration ... (check-in: f0e98310 user: altufaltu tags: trunk)
02:17
Add an "extended timestamp" field to generated ZIP archives. The extended timestamp is in UTC so it does not mangle the time when the server and client are in different timezones. Ticket [28044ab5a42b75] ... (check-in: 90048e0b user: drh tags: trunk)
2009-08-14
16:19
Add the --dotfiles option to the "add" command to cause fossil to include files whose name begins with "." which recursively adding files. Ticket [2e924cf9b74e]. ... (check-in: 5bc5e88c user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/zip.c.
46
47
48
49
50
51
52



53
54
55
56
57
58
59
60
61
62

63
64
65
66
67
68
69
** Variables in which to accumulate a growing ZIP archive.
*/
static Blob body;    /* The body of the ZIP archive */
static Blob toc;     /* The table of contents */
static int nEntry;   /* Number of files */
static int dosTime;  /* DOS-format time */
static int dosDate;  /* DOS-format date */




/*
** Initialize a new ZIP archive.
*/
void zip_open(void){
  blob_zero(&body);
  blob_zero(&toc);
  nEntry = 0;
  dosTime = 0;
  dosDate = 0;

}

/*
** Set the date and time values from an ISO8601 date string.
*/
void zip_set_timedate_from_str(const char *zDate){
  int y, m, d;







>
>
>










>







46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
** Variables in which to accumulate a growing ZIP archive.
*/
static Blob body;    /* The body of the ZIP archive */
static Blob toc;     /* The table of contents */
static int nEntry;   /* Number of files */
static int dosTime;  /* DOS-format time */
static int dosDate;  /* DOS-format date */
static int unixTime; /* Seconds since 1970 */
static int nDir;     /* Number of entries in azDir[] */
static char **azDir; /* Directory names already added to the archive */

/*
** Initialize a new ZIP archive.
*/
void zip_open(void){
  blob_zero(&body);
  blob_zero(&toc);
  nEntry = 0;
  dosTime = 0;
  dosDate = 0;
  unixTime = 0;
}

/*
** Set the date and time values from an ISO8601 date string.
*/
void zip_set_timedate_from_str(const char *zDate){
  int y, m, d;
82
83
84
85
86
87
88



























89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105



106
107

108
109
110
111
112








113

114
115
116
117
118
119
120
121







122
123
124
125
126
127

128

129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

181
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
210
211
212

213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232






233
234
235
236
237
238
239
/*
** Set the date and time from a julian day number.
*/
void zip_set_timedate(double rDate){
  char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate);
  zip_set_timedate_from_str(zDate);
  free(zDate);



























}

/*
** Append a single file to a growing ZIP archive.
**
** pFile is the file to be appended.  zName is the name
** that the file should be saved as.
*/
void zip_add_file(const char *zName, const Blob *pFile){
  z_stream stream;
  int nameLen;
  int skip;
  int toOut;
  int iStart;
  int iCRC;
  int nByte;
  int nByteCompr;



  char *z;
  char zHdr[30];

  char zBuf[100];
  char zOutBuf[100000];

  /* Fill in as much of the header as we know.
  */








  nameLen = strlen(zName);

  put32(&zHdr[0], 0x04034b50);
  put16(&zHdr[4], 0x0014);
  put16(&zHdr[6], 0);
  put16(&zHdr[8], 8);
  put16(&zHdr[10], dosTime);
  put16(&zHdr[12], dosDate);
  put16(&zHdr[26], nameLen);
  put16(&zHdr[28], 0);








  /* Write the header and filename.
  */
  iStart = blob_size(&body);
  blob_append(&body, zHdr, 30);
  blob_append(&body, zName, nameLen);



  /* The first two bytes that come out of the deflate compressor are
  ** some kind of header that ZIP does not use.  So skip the first two
  ** output bytes.
  */
  skip = 2;

  /* Write the compressed file.  Compute the CRC as we progress.
  */
  stream.zalloc = (alloc_func)0;
  stream.zfree = (free_func)0;
  stream.opaque = 0;
  stream.avail_in = blob_size(pFile);
  stream.next_in = (unsigned char*)blob_buffer(pFile);
  stream.avail_out = sizeof(zOutBuf);
  stream.next_out = (unsigned char*)zOutBuf;
  deflateInit(&stream, 9);
  iCRC = crc32(0, stream.next_in, stream.avail_in);
  while( stream.avail_in>0 ){
    deflate(&stream, 0);
    toOut = sizeof(zOutBuf) - stream.avail_out;
    if( toOut>skip ){
      blob_append(&body, &zOutBuf[skip], toOut - skip);
      skip = 0;
    }else{
      skip -= toOut;
    }
    stream.avail_out = sizeof(zOutBuf);
    stream.next_out = (unsigned char*)zOutBuf;
  }
  do{
    stream.avail_out = sizeof(zOutBuf);
    stream.next_out = (unsigned char*)zOutBuf;
    deflate(&stream, Z_FINISH);
    toOut = sizeof(zOutBuf) - stream.avail_out;
    if( toOut>skip ){
      blob_append(&body, &zOutBuf[skip], toOut - skip);
      skip = 0;
    }else{
      skip -= toOut;
    }
  }while( stream.avail_out==0 );
  nByte = stream.total_in;
  nByteCompr = stream.total_out - 2;
  deflateEnd(&stream);

  /* Go back and write the header, now that we know the compressed file size.
  */
  z = &blob_buffer(&body)[iStart];
  put32(&z[14], iCRC);
  put32(&z[18], nByteCompr);
  put32(&z[22], nByte);


  /* Make an entry in the tables of contents
  */
  memset(zBuf, 0, sizeof(zBuf));
  put32(&zBuf[0], 0x02014b50);
  put16(&zBuf[4], 0x0317);
  put16(&zBuf[6], 0x0014);
  put16(&zBuf[8], 0);
  put16(&zBuf[10], 0x0008);
  put16(&zBuf[12], dosTime);
  put16(&zBuf[14], dosDate);
  put32(&zBuf[16], iCRC);
  put32(&zBuf[20], nByteCompr);
  put32(&zBuf[24], nByte);
  put16(&zBuf[28], nameLen);
  put16(&zBuf[30], 0);
  put16(&zBuf[32], 0);
  put16(&zBuf[34], 0);
  put16(&zBuf[36], 0);
  put32(&zBuf[38], ((unsigned)(0100000 | 0644))<<16);
  put32(&zBuf[42], iStart);
  blob_append(&toc, zBuf, 46);
  blob_append(&toc, zName, nameLen);


  nEntry++;
}


/*
** Write the ZIP archive into the given BLOB.
*/
void zip_close(Blob *pZip){
  int iTocStart;
  int iTocEnd;

  char zBuf[30];

  iTocStart = blob_size(&body);
  blob_append(&body, blob_buffer(&toc), blob_size(&toc));
  iTocEnd = blob_size(&body);

  memset(zBuf, 0, sizeof(zBuf));
  put32(&zBuf[0], 0x06054b50);
  put16(&zBuf[4], 0);
  put16(&zBuf[6], 0);
  put16(&zBuf[8], nEntry);
  put16(&zBuf[10], nEntry);
  put32(&zBuf[12], iTocEnd - iTocStart);
  put32(&zBuf[16], iTocStart);
  put16(&zBuf[20], 0);
  blob_append(&body, zBuf, 22);
  blob_reset(&toc);
  *pZip = body;
  blob_zero(&body);
  nEntry = 0;






}

/*
** COMMAND: test-filezip
**
** Generate a ZIP archive specified by the first argument that
** contains files given in the second and subsequent arguments.







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>














|
|
|
>
>
>


>





>
>
>
>
>
>
>
>

>

|

|



|
>
>
>
>
>
>
>






>

>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>





|

|






|



|



>
>










>




















>
>
>
>
>
>







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*
** Set the date and time from a julian day number.
*/
void zip_set_timedate(double rDate){
  char *zDate = db_text(0, "SELECT datetime(%.17g)", rDate);
  zip_set_timedate_from_str(zDate);
  free(zDate);
  unixTime = (rDate - 2440587.5)*86400.0;
}

/*
** If the given filename includes one or more directory entries, make
** sure the directories are already in the archive.  If they are not
** in the archive, add them.
*/
void zip_add_folders(char *zName){
  int i, c;
  int j;
  for(i=0; zName[i]; i++){
    if( zName[i]=='/' ){
      c = zName[i+1];
      zName[i+1] = 0;
      for(j=0; j<nDir; j++){
        if( strcmp(zName, azDir[j])==0 ) break;
      }
      if( j>=nDir ){
        nDir++;
        azDir = realloc(azDir, nDir);
        azDir[j] = sqlite3_mprintf("%s", zName);
        zip_add_file(zName, 0);
      }
      zName[i+1] = c;
    }
  }
}

/*
** Append a single file to a growing ZIP archive.
**
** pFile is the file to be appended.  zName is the name
** that the file should be saved as.
*/
void zip_add_file(const char *zName, const Blob *pFile){
  z_stream stream;
  int nameLen;
  int skip;
  int toOut;
  int iStart;
  int iCRC = 0;
  int nByte = 0;
  int nByteCompr = 0;
  int nBlob;                 /* Size of the blob */
  int iMethod;               /* Compression method. */
  int iMode = 0644;          /* Access permissions */
  char *z;
  char zHdr[30];
  char zExTime[13];
  char zBuf[100];
  char zOutBuf[100000];

  /* Fill in as much of the header as we know.
  */
  nBlob = pFile ? blob_size(pFile) : 0;
  if( nBlob>0 ){
    iMethod = 8;
    iMode = 0100644;
  }else{
    iMethod = 0;
    iMode = 040755;
  }
  nameLen = strlen(zName);
  memset(zHdr, 0, sizeof(zHdr));
  put32(&zHdr[0], 0x04034b50);
  put16(&zHdr[4], 0x000a);
  put16(&zHdr[6], 0);
  put16(&zHdr[8], iMethod);
  put16(&zHdr[10], dosTime);
  put16(&zHdr[12], dosDate);
  put16(&zHdr[26], nameLen);
  put16(&zHdr[28], 13);
  
  put16(&zExTime[0], 0x5455);
  put16(&zExTime[2], 9);
  zExTime[4] = 3;
  put32(&zExTime[5], unixTime);
  put32(&zExTime[9], unixTime);
  

  /* Write the header and filename.
  */
  iStart = blob_size(&body);
  blob_append(&body, zHdr, 30);
  blob_append(&body, zName, nameLen);
  blob_append(&body, zExTime, 13);

  if( nBlob>0 ){
    /* The first two bytes that come out of the deflate compressor are
    ** some kind of header that ZIP does not use.  So skip the first two
    ** output bytes.
    */
    skip = 2;
  
    /* Write the compressed file.  Compute the CRC as we progress.
    */
    stream.zalloc = (alloc_func)0;
    stream.zfree = (free_func)0;
    stream.opaque = 0;
    stream.avail_in = blob_size(pFile);
    stream.next_in = (unsigned char*)blob_buffer(pFile);
    stream.avail_out = sizeof(zOutBuf);
    stream.next_out = (unsigned char*)zOutBuf;
    deflateInit(&stream, 9);
    iCRC = crc32(0, stream.next_in, stream.avail_in);
    while( stream.avail_in>0 ){
      deflate(&stream, 0);
      toOut = sizeof(zOutBuf) - stream.avail_out;
      if( toOut>skip ){
        blob_append(&body, &zOutBuf[skip], toOut - skip);
        skip = 0;
      }else{
        skip -= toOut;
      }
      stream.avail_out = sizeof(zOutBuf);
      stream.next_out = (unsigned char*)zOutBuf;
    }
    do{
      stream.avail_out = sizeof(zOutBuf);
      stream.next_out = (unsigned char*)zOutBuf;
      deflate(&stream, Z_FINISH);
      toOut = sizeof(zOutBuf) - stream.avail_out;
      if( toOut>skip ){
        blob_append(&body, &zOutBuf[skip], toOut - skip);
        skip = 0;
      }else{
        skip -= toOut;
      }
    }while( stream.avail_out==0 );
    nByte = stream.total_in;
    nByteCompr = stream.total_out - 2;
    deflateEnd(&stream);
  
    /* Go back and write the header, now that we know the compressed file size.
    */
    z = &blob_buffer(&body)[iStart];
    put32(&z[14], iCRC);
    put32(&z[18], nByteCompr);
    put32(&z[22], nByte);
  }
  
  /* Make an entry in the tables of contents
  */
  memset(zBuf, 0, sizeof(zBuf));
  put32(&zBuf[0], 0x02014b50);
  put16(&zBuf[4], 0x0317);
  put16(&zBuf[6], 0x000a);
  put16(&zBuf[8], 0);
  put16(&zBuf[10], iMethod);
  put16(&zBuf[12], dosTime);
  put16(&zBuf[14], dosDate);
  put32(&zBuf[16], iCRC);
  put32(&zBuf[20], nByteCompr);
  put32(&zBuf[24], nByte);
  put16(&zBuf[28], nameLen);
  put16(&zBuf[30], 9);
  put16(&zBuf[32], 0);
  put16(&zBuf[34], 0);
  put16(&zBuf[36], 0);
  put32(&zBuf[38], ((unsigned)iMode)<<16);
  put32(&zBuf[42], iStart);
  blob_append(&toc, zBuf, 46);
  blob_append(&toc, zName, nameLen);
  put16(&zExTime[2], 5);
  blob_append(&toc, zExTime, 9);
  nEntry++;
}


/*
** Write the ZIP archive into the given BLOB.
*/
void zip_close(Blob *pZip){
  int iTocStart;
  int iTocEnd;
  int i;
  char zBuf[30];

  iTocStart = blob_size(&body);
  blob_append(&body, blob_buffer(&toc), blob_size(&toc));
  iTocEnd = blob_size(&body);

  memset(zBuf, 0, sizeof(zBuf));
  put32(&zBuf[0], 0x06054b50);
  put16(&zBuf[4], 0);
  put16(&zBuf[6], 0);
  put16(&zBuf[8], nEntry);
  put16(&zBuf[10], nEntry);
  put32(&zBuf[12], iTocEnd - iTocStart);
  put32(&zBuf[16], iTocStart);
  put16(&zBuf[20], 0);
  blob_append(&body, zBuf, 22);
  blob_reset(&toc);
  *pZip = body;
  blob_zero(&body);
  nEntry = 0;
  for(i=0; i<nDir; i++){
    sqlite3_free(azDir[i]);
  }
  free(azDir);
  nDir = 0;
  azDir = 0;
}

/*
** COMMAND: test-filezip
**
** Generate a ZIP archive specified by the first argument that
** contains files given in the second and subsequent arguments.
294
295
296
297
298
299
300

301
302
303


304
305
306
307
308
309

310
311
312
313
314
315
316
317


318
319
320
321
322
323
324

  if( zDir && zDir[0] ){
    blob_appendf(&filename, "%s/", zDir);
  }
  nPrefix = blob_size(&filename);

  if( manifest_parse(&m, &mfile) ){

    zip_set_timedate(m.rDate);
    blob_append(&filename, "manifest", -1);
    zip_add_file(blob_str(&filename), &file);


    sha1sum_blob(&file, &hash);
    blob_reset(&file);
    blob_append(&hash, "\n", 1);
    blob_resize(&filename, nPrefix);
    blob_append(&filename, "manifest.uuid", -1);
    zip_add_file(blob_str(&filename), &hash);

    blob_reset(&hash);
    for(i=0; i<m.nFile; i++){
      int fid = uuid_to_rid(m.aFile[i].zUuid, 0);
      if( fid ){
        content_get(fid, &file);
        blob_resize(&filename, nPrefix);
        blob_append(&filename, m.aFile[i].zName, -1);
        zip_add_file(blob_str(&filename), &file);


        blob_reset(&file);
      }
    }
    manifest_clear(&m);
  }else{
    blob_reset(&mfile);
    blob_reset(&file);







>


|
>
>





|
>







|
>
>







357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393

  if( zDir && zDir[0] ){
    blob_appendf(&filename, "%s/", zDir);
  }
  nPrefix = blob_size(&filename);

  if( manifest_parse(&m, &mfile) ){
    char *zName;
    zip_set_timedate(m.rDate);
    blob_append(&filename, "manifest", -1);
    zName = blob_str(&filename);
    zip_add_folders(zName);
    zip_add_file(zName, &file);
    sha1sum_blob(&file, &hash);
    blob_reset(&file);
    blob_append(&hash, "\n", 1);
    blob_resize(&filename, nPrefix);
    blob_append(&filename, "manifest.uuid", -1);
    zName = blob_str(&filename);
    zip_add_file(zName, &hash);
    blob_reset(&hash);
    for(i=0; i<m.nFile; i++){
      int fid = uuid_to_rid(m.aFile[i].zUuid, 0);
      if( fid ){
        content_get(fid, &file);
        blob_resize(&filename, nPrefix);
        blob_append(&filename, m.aFile[i].zName, -1);
        zName = blob_str(&filename);
        zip_add_folders(zName);
        zip_add_file(zName, &file);
        blob_reset(&file);
      }
    }
    manifest_clear(&m);
  }else{
    blob_reset(&mfile);
    blob_reset(&file);