MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
azio.c
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 */
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 
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 */
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 */
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 */
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 */
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 
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  */
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 */
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 */
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 */
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 
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 
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 */
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 
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 }