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