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