1 /*
2 azio is a modified version of gzio. It makes use of mysys and removes mallocs.
3 -Brian Aker
4 */
5
6 /* gzio.c -- IO on .gz files
7 * Copyright (C) 1995-2005 Jean-loup Gailly.
8 * For conditions of distribution and use, see copyright notice in zlib.h
9 *
10 */
11
12 /* @(#) $Id$ */
13
14 #include "azlib.h"
15
16 #include <stdio.h>
17 #include <string.h>
18
19 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
20 static int const az_magic[3] = {0xfe, 0x03, 0x01}; /* az magic header */
21
22 /* gzip flag uchar */
23 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
24 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
25 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
26 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
27 #define COMMENT 0x10 /* bit 4 set: file comment present */
28 #define RESERVED 0xE0 /* bits 5..7: reserved */
29
30 int az_open(azio_stream *s, const char *path, int Flags, File fd);
31 int do_flush(azio_stream *file, int flush);
32 int get_byte(azio_stream *s);
33 void check_header(azio_stream *s);
34 int write_header(azio_stream *s);
35 int destroy(azio_stream *s);
36 void putLong(File file, uLong x);
37 uLong getLong(azio_stream *s);
38 void read_header(azio_stream *s, unsigned char *buffer);
39
40 #ifdef HAVE_PSI_INTERFACE
41 extern PSI_file_key arch_key_file_data;
42 #endif
43
44 /* ===========================================================================
45 Opens a gzip (.gz) file for reading or writing. The mode parameter
46 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
47 or path name (if fd == -1).
48 az_open returns NULL if the file could not be opened or if there was
49 insufficient memory to allocate the (de)compression state; errno
50 can be checked to distinguish the two cases (if errno is zero, the
51 zlib error is Z_MEM_ERROR).
52 */
az_open(azio_stream * s,const char * path,int Flags,File fd)53 int az_open (azio_stream *s, const char *path, int Flags, File fd)
54 {
55 int err;
56 int level = Z_DEFAULT_COMPRESSION; /* compression level */
57 int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
58
59 memset(s, 0, sizeof(azio_stream));
60 s->stream.next_in = s->inbuf;
61 s->stream.next_out = s->outbuf;
62 DBUG_ASSERT(s->z_err == Z_OK);
63 s->back = EOF;
64 s->crc = crc32(0L, Z_NULL, 0);
65 s->mode = 'r';
66 /* this needs to be a define to version */
67 s->version = (unsigned char)az_magic[1];
68 s->minor_version= (unsigned char) az_magic[2]; /* minor version */
69 DBUG_ASSERT(s->dirty == AZ_STATE_CLEAN);
70
71 /*
72 We do our own version of append by nature.
73 We must always have write access to take card of the header.
74 */
75 DBUG_ASSERT(Flags | O_APPEND);
76 DBUG_ASSERT(Flags | O_WRONLY);
77
78 if (Flags & O_RDWR)
79 s->mode = 'w';
80
81 if (s->mode == 'w')
82 {
83 err = deflateInit2(&(s->stream), level,
84 Z_DEFLATED, -MAX_WBITS, 8, strategy);
85 /* windowBits is passed < 0 to suppress zlib header */
86
87 s->stream.next_out = s->outbuf;
88 if (err != Z_OK)
89 {
90 destroy(s);
91 return Z_NULL;
92 }
93 } else {
94 s->stream.next_in = s->inbuf;
95
96 err = inflateInit2(&(s->stream), -MAX_WBITS);
97 /* windowBits is passed < 0 to tell that there is no zlib header.
98 * Note that in this case inflate *requires* an extra "dummy" byte
99 * after the compressed stream in order to complete decompression and
100 * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
101 * present after the compressed stream.
102 */
103 if (err != Z_OK)
104 {
105 destroy(s);
106 return Z_NULL;
107 }
108 }
109 s->stream.avail_out = AZ_BUFSIZE_WRITE;
110
111 errno = 0;
112 s->file = fd < 0 ? mysql_file_open(arch_key_file_data, path, Flags, MYF(0)) : fd;
113 DBUG_EXECUTE_IF("simulate_archive_open_failure",
114 {
115 if (s->file >= 0)
116 {
117 my_close(s->file, MYF(0));
118 s->file= -1;
119 my_errno= EMFILE;
120 }
121 });
122
123 if (s->file < 0 )
124 {
125 destroy(s);
126 return Z_NULL;
127 }
128
129 if (Flags & O_CREAT || Flags & O_TRUNC)
130 {
131 s->dirty= 1; /* We create the file dirty */
132 s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
133 write_header(s);
134 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
135 }
136 else if (s->mode == 'w')
137 {
138 uchar buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
139 my_pread(s->file, buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
140 MYF(0));
141 read_header(s, buffer); /* skip the .az header */
142 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
143 }
144 else
145 {
146 check_header(s); /* skip the .az header */
147 }
148
149 return 1;
150 }
151
152
write_header(azio_stream * s)153 int write_header(azio_stream *s)
154 {
155 char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
156 char *ptr= buffer;
157
158 if (s->version == 1)
159 return 0;
160
161 s->block_size= AZ_BUFSIZE_WRITE;
162 s->version = (unsigned char)az_magic[1];
163 s->minor_version = (unsigned char)az_magic[2];
164
165
166 /* Write a very simple .az header: */
167 memset(buffer, 0, AZHEADER_SIZE + AZMETA_BUFFER_SIZE);
168 *(ptr + AZ_MAGIC_POS)= az_magic[0];
169 *(ptr + AZ_VERSION_POS)= (unsigned char)s->version;
170 *(ptr + AZ_MINOR_VERSION_POS)= (unsigned char)s->minor_version;
171 *(ptr + AZ_BLOCK_POS)= (unsigned char)(s->block_size/1024); /* Reserved for block size */
172 *(ptr + AZ_STRATEGY_POS)= (unsigned char)Z_DEFAULT_STRATEGY; /* Compression Type */
173
174 int4store(ptr + AZ_FRM_POS, s->frm_start_pos); /* FRM Block */
175 int4store(ptr + AZ_FRM_LENGTH_POS, s->frm_length); /* FRM Block */
176 int4store(ptr + AZ_COMMENT_POS, s->comment_start_pos); /* COMMENT Block */
177 int4store(ptr + AZ_COMMENT_LENGTH_POS, s->comment_length); /* COMMENT Block */
178 int4store(ptr + AZ_META_POS, 0); /* Meta Block */
179 int4store(ptr + AZ_META_LENGTH_POS, 0); /* Meta Block */
180 int8store(ptr + AZ_START_POS, (unsigned long long)s->start); /* Start of Data Block Index Block */
181 int8store(ptr + AZ_ROW_POS, (unsigned long long)s->rows); /* Start of Data Block Index Block */
182 int8store(ptr + AZ_FLUSH_POS, (unsigned long long)s->forced_flushes); /* Start of Data Block Index Block */
183 int8store(ptr + AZ_CHECK_POS, (unsigned long long)s->check_point); /* Start of Data Block Index Block */
184 int8store(ptr + AZ_AUTOINCREMENT_POS, (unsigned long long)s->auto_increment); /* Start of Data Block Index Block */
185 int4store(ptr+ AZ_LONGEST_POS , s->longest_row); /* Longest row */
186 int4store(ptr+ AZ_SHORTEST_POS, s->shortest_row); /* Shorest row */
187 int4store(ptr+ AZ_FRM_POS,
188 AZHEADER_SIZE + AZMETA_BUFFER_SIZE); /* FRM position */
189 *(ptr + AZ_DIRTY_POS)= (unsigned char)s->dirty; /* Start of Data Block Index Block */
190
191 /* Always begin at the begining, and end there as well */
192 return my_pwrite(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE,
193 0, MYF(MY_NABP)) ? 1 : 0;
194 }
195
196 /* ===========================================================================
197 Opens a gzip (.gz) file for reading or writing.
198 */
azopen(azio_stream * s,const char * path,int Flags)199 int azopen(azio_stream *s, const char *path, int Flags)
200 {
201 return az_open(s, path, Flags, -1);
202 }
203
204 /* ===========================================================================
205 Associate a gzFile with the file descriptor fd. fd is not dup'ed here
206 to mimic the behavio(u)r of fdopen.
207 */
azdopen(azio_stream * s,File fd,int Flags)208 int azdopen(azio_stream *s, File fd, int Flags)
209 {
210 if (fd < 0) return 0;
211
212 return az_open (s, NULL, Flags, fd);
213 }
214
215 /* ===========================================================================
216 Read a byte from a azio_stream; update next_in and avail_in. Return EOF
217 for end of file.
218 IN assertion: the stream s has been sucessfully opened for reading.
219 */
get_byte(s)220 int get_byte(s)
221 azio_stream *s;
222 {
223 if (s->z_eof) return EOF;
224 if (s->stream.avail_in == 0)
225 {
226 errno = 0;
227 s->stream.avail_in= (uInt) mysql_file_read(s->file, (uchar *)s->inbuf,
228 AZ_BUFSIZE_READ, MYF(0));
229 if (s->stream.avail_in == 0)
230 {
231 s->z_eof = 1;
232 return EOF;
233 }
234 else if (s->stream.avail_in == (uInt) -1)
235 {
236 s->z_eof= 1;
237 s->z_err= Z_ERRNO;
238 return EOF;
239 }
240 s->stream.next_in = s->inbuf;
241 }
242 s->stream.avail_in--;
243 return *(s->stream.next_in)++;
244 }
245
246 /* ===========================================================================
247 Check the gzip header of a azio_stream opened for reading. Set the stream
248 mode to transparent if the gzip magic header is not present; set s->err
249 to Z_DATA_ERROR if the magic header is present but the rest of the header
250 is incorrect.
251 IN assertion: the stream s has already been created sucessfully;
252 s->stream.avail_in is zero for the first time, but may be non-zero
253 for concatenated .gz files.
254 */
check_header(azio_stream * s)255 void check_header(azio_stream *s)
256 {
257 int method; /* method uchar */
258 int flags; /* flags uchar */
259 uInt len;
260 int c;
261
262 /* Assure two bytes in the buffer so we can peek ahead -- handle case
263 where first byte of header is at the end of the buffer after the last
264 gzip segment */
265 len = s->stream.avail_in;
266 if (len < 2) {
267 if (len) s->inbuf[0] = s->stream.next_in[0];
268 errno = 0;
269 len = (uInt)mysql_file_read(s->file, (uchar *)s->inbuf + len,
270 AZ_BUFSIZE_READ >> len, MYF(0));
271 if (len == (uInt)-1) s->z_err = Z_ERRNO;
272 s->stream.avail_in += len;
273 s->stream.next_in = s->inbuf;
274 if (s->stream.avail_in < 2) {
275 s->transparent = s->stream.avail_in;
276 return;
277 }
278 }
279
280 /* Peek ahead to check the gzip magic header */
281 if ( s->stream.next_in[0] == gz_magic[0] && s->stream.next_in[1] == gz_magic[1])
282 {
283 read_header(s, s->stream.next_in);
284 s->stream.avail_in -= 2;
285 s->stream.next_in += 2;
286
287 /* Check the rest of the gzip header */
288 method = get_byte(s);
289 flags = get_byte(s);
290 if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
291 s->z_err = Z_DATA_ERROR;
292 return;
293 }
294
295 /* Discard time, xflags and OS code: */
296 for (len = 0; len < 6; len++) (void)get_byte(s);
297
298 if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
299 len = (uInt)get_byte(s);
300 len += ((uInt)get_byte(s))<<8;
301 /* len is garbage if EOF but the loop below will quit anyway */
302 while (len-- != 0 && get_byte(s) != EOF) ;
303 }
304 if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
305 while ((c = get_byte(s)) != 0 && c != EOF) ;
306 }
307 if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
308 while ((c = get_byte(s)) != 0 && c != EOF) ;
309 }
310 if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
311 for (len = 0; len < 2; len++) (void)get_byte(s);
312 }
313 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
314 if (!s->start)
315 s->start= my_tell(s->file, MYF(0)) - s->stream.avail_in;
316 }
317 else if ( s->stream.next_in[0] == az_magic[0] && s->stream.next_in[1] == az_magic[1])
318 {
319 unsigned char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
320
321 for (len = 0; len < (AZHEADER_SIZE + AZMETA_BUFFER_SIZE); len++)
322 buffer[len]= get_byte(s);
323 s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
324 read_header(s, buffer);
325 for (; len < s->start; len++)
326 get_byte(s);
327 }
328 else
329 {
330 s->z_err = Z_OK;
331
332 return;
333 }
334 }
335
read_header(azio_stream * s,unsigned char * buffer)336 void read_header(azio_stream *s, unsigned char *buffer)
337 {
338 if (buffer[0] == az_magic[0] && buffer[1] == az_magic[1])
339 {
340 s->version= (unsigned int)buffer[AZ_VERSION_POS];
341 s->minor_version= (unsigned int)buffer[AZ_MINOR_VERSION_POS];
342 s->block_size= 1024 * buffer[AZ_BLOCK_POS];
343 s->start= (unsigned long long)uint8korr(buffer + AZ_START_POS);
344 s->rows= (unsigned long long)uint8korr(buffer + AZ_ROW_POS);
345 s->check_point= (unsigned long long)uint8korr(buffer + AZ_CHECK_POS);
346 s->forced_flushes= (unsigned long long)uint8korr(buffer + AZ_FLUSH_POS);
347 s->auto_increment= (unsigned long long)uint8korr(buffer + AZ_AUTOINCREMENT_POS);
348 s->longest_row= (unsigned int)uint4korr(buffer + AZ_LONGEST_POS);
349 s->shortest_row= (unsigned int)uint4korr(buffer + AZ_SHORTEST_POS);
350 s->frm_start_pos= (unsigned int)uint4korr(buffer + AZ_FRM_POS);
351 s->frm_length= (unsigned int)uint4korr(buffer + AZ_FRM_LENGTH_POS);
352 s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS);
353 s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS);
354 s->dirty= (unsigned int)buffer[AZ_DIRTY_POS];
355 }
356 else if (buffer[0] == gz_magic[0] && buffer[1] == gz_magic[1])
357 {
358 /*
359 Set version number to previous version (1).
360 */
361 s->version= 1;
362 s->auto_increment= 0;
363 s->frm_length= 0;
364 } else {
365 /*
366 Unknown version.
367 Most probably due to a corrupt archive.
368 */
369 s->dirty= AZ_STATE_DIRTY;
370 s->z_err= Z_VERSION_ERROR;
371 }
372 }
373
374 /* ===========================================================================
375 * Cleanup then free the given azio_stream. Return a zlib error code.
376 Try freeing in the reverse order of allocations.
377 */
destroy(s)378 int destroy (s)
379 azio_stream *s;
380 {
381 int err = Z_OK;
382
383 if (s->stream.state != NULL)
384 {
385 if (s->mode == 'w')
386 err = deflateEnd(&(s->stream));
387 else if (s->mode == 'r')
388 err = inflateEnd(&(s->stream));
389 }
390
391 if (s->file > 0 && my_close(s->file, MYF(0)))
392 err = Z_ERRNO;
393
394 s->file= -1;
395
396 if (s->z_err < 0) err = s->z_err;
397
398 return err;
399 }
400
401 /* ===========================================================================
402 Reads the given number of uncompressed bytes from the compressed file.
403 azread returns the number of bytes actually read (0 for end of file).
404 */
azread(azio_stream * s,voidp buf,size_t len,int * error)405 unsigned int ZEXPORT azread ( azio_stream *s, voidp buf, size_t len, int *error)
406 {
407 Bytef *start = (Bytef*)buf; /* starting point for crc computation */
408 Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
409 *error= 0;
410
411 if (s->mode != 'r')
412 {
413 *error= Z_STREAM_ERROR;
414 return 0;
415 }
416
417 if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
418 {
419 *error= s->z_err;
420 return 0;
421 }
422
423 if (s->z_err == Z_STREAM_END) /* EOF */
424 {
425 return 0;
426 }
427
428 next_out = (Byte*)buf;
429 s->stream.next_out = (Bytef*)buf;
430 s->stream.avail_out = len;
431
432 if (s->stream.avail_out && s->back != EOF) {
433 *next_out++ = s->back;
434 s->stream.next_out++;
435 s->stream.avail_out--;
436 s->back = EOF;
437 s->out++;
438 start++;
439 if (s->last) {
440 s->z_err = Z_STREAM_END;
441 {
442 return 1;
443 }
444 }
445 }
446
447 while (s->stream.avail_out != 0) {
448
449 if (s->transparent) {
450 /* Copy first the lookahead bytes: */
451 uInt n = s->stream.avail_in;
452 if (n > s->stream.avail_out) n = s->stream.avail_out;
453 if (n > 0) {
454 memcpy(s->stream.next_out, s->stream.next_in, n);
455 next_out += n;
456 s->stream.next_out = (Bytef *)next_out;
457 s->stream.next_in += n;
458 s->stream.avail_out -= n;
459 s->stream.avail_in -= n;
460 }
461 if (s->stream.avail_out > 0)
462 {
463 s->stream.avail_out -=
464 (uInt)mysql_file_read(s->file, (uchar *)next_out,
465 s->stream.avail_out, MYF(0));
466 }
467 len -= s->stream.avail_out;
468 s->in += len;
469 s->out += len;
470 if (len == 0) s->z_eof = 1;
471 {
472 return len;
473 }
474 }
475 if (s->stream.avail_in == 0 && !s->z_eof) {
476
477 errno = 0;
478 s->stream.avail_in = (uInt)mysql_file_read(s->file, (uchar *)s->inbuf,
479 AZ_BUFSIZE_READ, MYF(0));
480 if (s->stream.avail_in == 0)
481 {
482 s->z_eof = 1;
483 }
484 s->stream.next_in = (Bytef *)s->inbuf;
485 }
486 s->in += s->stream.avail_in;
487 s->out += s->stream.avail_out;
488 s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
489 s->in -= s->stream.avail_in;
490 s->out -= s->stream.avail_out;
491
492 if (s->z_err == Z_STREAM_END) {
493 /* Check CRC and original size */
494 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
495 start = s->stream.next_out;
496
497 if (getLong(s) != s->crc) {
498 s->z_err = Z_DATA_ERROR;
499 } else {
500 (void)getLong(s);
501 /* The uncompressed length returned by above getlong() may be
502 * different from s->out in case of concatenated .gz files.
503 * Check for such files:
504 */
505 check_header(s);
506 if (s->z_err == Z_OK)
507 {
508 inflateReset(&(s->stream));
509 s->crc = crc32(0L, Z_NULL, 0);
510 }
511 }
512 }
513 if (s->z_err != Z_OK || s->z_eof) break;
514 }
515 s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
516
517 if (len == s->stream.avail_out &&
518 (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
519 {
520 *error= s->z_err;
521
522 return 0;
523 }
524
525 return (len - s->stream.avail_out);
526 }
527
528
529 /* ===========================================================================
530 Writes the given number of uncompressed bytes into the compressed file.
531 azwrite returns the number of bytes actually written (0 in case of error).
532 */
azwrite(azio_stream * s,const voidp buf,unsigned int len)533 unsigned int azwrite (azio_stream *s, const voidp buf, unsigned int len)
534 {
535 s->stream.next_in = (Bytef*)buf;
536 s->stream.avail_in = len;
537
538 s->rows++;
539
540 while (s->stream.avail_in != 0)
541 {
542 if (s->stream.avail_out == 0)
543 {
544
545 s->stream.next_out = s->outbuf;
546 if (mysql_file_write(s->file, (uchar *)s->outbuf, AZ_BUFSIZE_WRITE,
547 MYF(0)) != AZ_BUFSIZE_WRITE)
548 {
549 s->z_err = Z_ERRNO;
550 break;
551 }
552 s->stream.avail_out = AZ_BUFSIZE_WRITE;
553 }
554 s->in += s->stream.avail_in;
555 s->out += s->stream.avail_out;
556 s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
557 s->in -= s->stream.avail_in;
558 s->out -= s->stream.avail_out;
559 if (s->z_err != Z_OK) break;
560 }
561 s->crc = crc32(s->crc, (const Bytef *)buf, len);
562
563 if (len > s->longest_row)
564 s->longest_row= len;
565
566 if (len < s->shortest_row || !(s->shortest_row))
567 s->shortest_row= len;
568
569 return (unsigned int)(len - s->stream.avail_in);
570 }
571
572
573 /* ===========================================================================
574 Flushes all pending output into the compressed file. The parameter
575 flush is as in the deflate() function.
576 */
do_flush(azio_stream * s,int flush)577 int do_flush (azio_stream *s, int flush)
578 {
579 uInt len;
580 int done = 0;
581 my_off_t afterwrite_pos;
582
583 if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
584
585 s->stream.avail_in = 0; /* should be zero already anyway */
586
587 for (;;)
588 {
589 len = AZ_BUFSIZE_WRITE - s->stream.avail_out;
590
591 if (len != 0)
592 {
593 s->check_point= my_tell(s->file, MYF(0));
594 if ((uInt)mysql_file_write(s->file, (uchar *)s->outbuf, len, MYF(0)) != len)
595 {
596 s->z_err = Z_ERRNO;
597 return Z_ERRNO;
598 }
599 s->stream.next_out = s->outbuf;
600 s->stream.avail_out = AZ_BUFSIZE_WRITE;
601 }
602 if (done) break;
603 s->out += s->stream.avail_out;
604 s->z_err = deflate(&(s->stream), flush);
605 s->out -= s->stream.avail_out;
606
607 /* Ignore the second of two consecutive flushes: */
608 if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
609
610 /* deflate has finished flushing only when it hasn't used up
611 * all the available space in the output buffer:
612 */
613 done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
614
615 if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
616 }
617
618 if (flush == Z_FINISH)
619 s->dirty= AZ_STATE_CLEAN; /* Mark it clean, we should be good now */
620 else
621 s->dirty= AZ_STATE_SAVED; /* Mark it clean, we should be good now */
622
623 afterwrite_pos= my_tell(s->file, MYF(0));
624 write_header(s);
625 my_seek(s->file, afterwrite_pos, SEEK_SET, MYF(0));
626
627 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
628 }
629
azflush(s,flush)630 int ZEXPORT azflush (s, flush)
631 azio_stream *s;
632 int flush;
633 {
634 int err;
635
636 if (s->mode == 'r')
637 {
638 unsigned char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
639 my_pread(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
640 MYF(0));
641 read_header(s, buffer); /* skip the .az header */
642
643 return Z_OK;
644 }
645 else
646 {
647 s->forced_flushes++;
648 err= do_flush(s, flush);
649
650 if (err) return err;
651 my_sync(s->file, MYF(0));
652 return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
653 }
654 }
655
656 /* ===========================================================================
657 Rewinds input file.
658 */
azrewind(s)659 int azrewind (s)
660 azio_stream *s;
661 {
662 if (s == NULL || s->mode != 'r') return -1;
663
664 s->z_err = Z_OK;
665 s->z_eof = 0;
666 s->back = EOF;
667 s->stream.avail_in = 0;
668 s->stream.next_in = (Bytef *)s->inbuf;
669 s->crc = crc32(0L, Z_NULL, 0);
670 if (!s->transparent) (void)inflateReset(&s->stream);
671 s->in = 0;
672 s->out = 0;
673 return my_seek(s->file, (int)s->start, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR;
674 }
675
676 /* ===========================================================================
677 Sets the starting position for the next azread or azwrite on the given
678 compressed file. The offset represents a number of bytes in the
679 azseek returns the resulting offset location as measured in bytes from
680 the beginning of the uncompressed stream, or -1 in case of error.
681 SEEK_END is not implemented, returns error.
682 In this version of the library, azseek can be extremely slow.
683 */
azseek(s,offset,whence)684 my_off_t azseek (s, offset, whence)
685 azio_stream *s;
686 my_off_t offset;
687 int whence;
688 {
689
690 if (s == NULL || whence == SEEK_END ||
691 s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
692 return -1L;
693 }
694
695 if (s->mode == 'w')
696 {
697 if (whence == SEEK_SET)
698 offset -= s->in;
699
700 /* At this point, offset is the number of zero bytes to write. */
701 /* There was a zmemzero here if inbuf was null -Brian */
702 while (offset > 0)
703 {
704 uInt size = AZ_BUFSIZE_READ;
705 if (offset < AZ_BUFSIZE_READ) size = (uInt)offset;
706
707 size = azwrite(s, s->inbuf, size);
708 if (size == 0) return -1L;
709
710 offset -= size;
711 }
712 return s->in;
713 }
714 /* Rest of function is for reading only */
715
716 /* compute absolute position */
717 if (whence == SEEK_CUR) {
718 offset += s->out;
719 }
720
721 if (s->transparent) {
722 /* map to my_seek */
723 s->back = EOF;
724 s->stream.avail_in = 0;
725 s->stream.next_in = (Bytef *)s->inbuf;
726 if (my_seek(s->file, offset, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) return -1L;
727
728 s->in = s->out = offset;
729 return offset;
730 }
731
732 /* For a negative seek, rewind and use positive seek */
733 if (offset >= s->out) {
734 offset -= s->out;
735 } else if (azrewind(s)) {
736 return -1L;
737 }
738 /* offset is now the number of bytes to skip. */
739
740 if (offset && s->back != EOF) {
741 s->back = EOF;
742 s->out++;
743 offset--;
744 if (s->last) s->z_err = Z_STREAM_END;
745 }
746 while (offset > 0) {
747 int error;
748 unsigned int size = AZ_BUFSIZE_WRITE;
749 if (offset < AZ_BUFSIZE_WRITE) size = (int)offset;
750
751 size = azread(s, s->outbuf, size, &error);
752 if (error < 0) return -1L;
753 offset -= size;
754 }
755 return s->out;
756 }
757
758 /* ===========================================================================
759 Returns the starting position for the next azread or azwrite on the
760 given compressed file. This position represents a number of bytes in the
761 uncompressed data stream.
762 */
aztell(file)763 my_off_t ZEXPORT aztell (file)
764 azio_stream *file;
765 {
766 return azseek(file, 0L, SEEK_CUR);
767 }
768
769
770 /* ===========================================================================
771 Outputs a long in LSB order to the given file
772 */
putLong(File file,uLong x)773 void putLong (File file, uLong x)
774 {
775 int n;
776 uchar buffer[1];
777
778 for (n = 0; n < 4; n++)
779 {
780 buffer[0]= (int)(x & 0xff);
781 mysql_file_write(file, buffer, 1, MYF(0));
782 x >>= 8;
783 }
784 }
785
786 /* ===========================================================================
787 Reads a long in LSB order from the given azio_stream. Sets z_err in case
788 of error.
789 */
getLong(azio_stream * s)790 uLong getLong (azio_stream *s)
791 {
792 uLong x = (uLong)get_byte(s);
793 int c;
794
795 x += ((uLong)get_byte(s))<<8;
796 x += ((uLong)get_byte(s))<<16;
797 c = get_byte(s);
798 if (c == EOF) s->z_err = Z_DATA_ERROR;
799 x += ((uLong)c)<<24;
800 return x;
801 }
802
803 /* ===========================================================================
804 Flushes all pending output if necessary, closes the compressed file
805 and deallocates all the (de)compression state.
806 */
azclose(azio_stream * s)807 int azclose (azio_stream *s)
808 {
809
810 if (s == NULL) return Z_STREAM_ERROR;
811
812 if (s->file < 1) return Z_OK;
813
814 if (s->mode == 'w')
815 {
816 if (do_flush(s, Z_FINISH) != Z_OK)
817 return destroy(s);
818
819 putLong(s->file, s->crc);
820 putLong(s->file, (uLong)(s->in & 0xffffffff));
821 s->dirty= AZ_STATE_CLEAN;
822 s->check_point= my_tell(s->file, MYF(0));
823 write_header(s);
824 }
825
826 return destroy(s);
827 }
828
829 /*
830 Though this was added to support MySQL's FRM file, anything can be
831 stored in this location.
832 */
azwrite_frm(azio_stream * s,char * blob,unsigned int length)833 int azwrite_frm(azio_stream *s, char *blob, unsigned int length)
834 {
835 if (s->mode == 'r')
836 return 1;
837
838 if (s->rows > 0)
839 return 1;
840
841 s->frm_start_pos= (uint) s->start;
842 s->frm_length= length;
843 s->start+= length;
844
845 if (my_pwrite(s->file, (uchar*) blob, s->frm_length,
846 s->frm_start_pos, MYF(MY_NABP)) ||
847 write_header(s) ||
848 (my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR))
849 return 1;
850
851 return 0;
852 }
853
azread_frm(azio_stream * s,char * blob)854 int azread_frm(azio_stream *s, char *blob)
855 {
856 return my_pread(s->file, (uchar*) blob, s->frm_length,
857 s->frm_start_pos, MYF(MY_NABP)) ? 1 : 0;
858 }
859
860
861 /*
862 Simple comment field
863 */
azwrite_comment(azio_stream * s,char * blob,unsigned int length)864 int azwrite_comment(azio_stream *s, char *blob, unsigned int length)
865 {
866 if (s->mode == 'r')
867 return 1;
868
869 if (s->rows > 0)
870 return 1;
871
872 s->comment_start_pos= (uint) s->start;
873 s->comment_length= length;
874 s->start+= length;
875
876 my_pwrite(s->file, (uchar*) blob, s->comment_length, s->comment_start_pos,
877 MYF(0));
878
879 write_header(s);
880 my_seek(s->file, 0, MY_SEEK_END, MYF(0));
881
882 return 0;
883 }
884
azread_comment(azio_stream * s,char * blob)885 int azread_comment(azio_stream *s, char *blob)
886 {
887 my_pread(s->file, (uchar*) blob, s->comment_length, s->comment_start_pos,
888 MYF(0));
889
890 return 0;
891 }
892