MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ndbzio.c
1 /*
2  Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
3 
4  This program is free software; you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 /*
19  ndbzio is a modified version of azio with a cleaner interface.
20 
21  - Magnus BlĂ„udd
22 */
23 
24 /*
25  azio is a modified version of gzio. It makes use of mysys and removes mallocs.
26  -Brian Aker
27 */
28 
29 /*
30  * This version has been hacked around by Stewart Smith to get the following:
31  * - Direct IO (512 byte aligned IO, IO in multibles of 512 bytes)
32  * - No memory dynamic memory allocation (all done on startup)
33  * - A kinda broken flush (see point 1: O_DIRECT) :)
34  */
35 
36 /* gzio.c -- IO on .gz files
37  * Copyright (C) 1995-2005 Jean-loup Gailly.
38  * For conditions of distribution and use, see copyright notice in zlib.h
39  *
40  */
41 
42 #include <ndb_global.h>
43 
48 #include "../../../../zlib/zutil.h"
49 #include "../../../../zlib/zconf.h"
50 #include "../../../../zlib/inftrees.h"
51 #include "../../../../zlib/inflate.h"
52 #include "../../../../zlib/deflate.h"
53 
54 #include <util/ndbzio.h>
55 
56 #include <my_sys.h>
57 
58 #ifdef HAVE_VALGRIND
59 #include <valgrind/memcheck.h>
60 #else
61 #define VALGRIND_MAKE_MEM_DEFINED(a,b) do {} while(0);
62 #define VALGRIND_MAKE_MEM_NOACCESS(a,b) do {} while(0);
63 #endif
64 
65 /* Start of MySQL Specific Information */
66 
67 
68 #define AZHEADER_SIZE 29
69 #define AZMETA_BUFFER_SIZE 512-AZHEADER_SIZE
70 
71 #define AZ_MAGIC_POS 0
72 #define AZ_VERSION_POS 1
73 #define AZ_MINOR_VERSION_POS 2
74 #define AZ_BLOCK_POS 3
75 #define AZ_STRATEGY_POS 4
76 #define AZ_FRM_POS 5
77 #define AZ_FRM_LENGTH_POS 9
78 #define AZ_META_POS 13
79 #define AZ_META_LENGTH_POS 17
80 #define AZ_START_POS 21
81 #define AZ_ROW_POS 29
82 #define AZ_FLUSH_POS 37
83 #define AZ_CHECK_POS 45
84 #define AZ_AUTOINCREMENT_POS 53
85 #define AZ_LONGEST_POS 61
86 #define AZ_SHORTEST_POS 65
87 #define AZ_COMMENT_POS 69
88 #define AZ_COMMENT_LENGTH_POS 73
89 #define AZ_DIRTY_POS 77
90 
91 
92 /*
93  Flags for state
94 */
95 #define AZ_STATE_CLEAN 0
96 #define AZ_STATE_DIRTY 1
97 #define AZ_STATE_SAVED 2
98 #define AZ_STATE_CRASHED 3
99 
100 
101 static int const gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */
102 static int const az_magic[3] = {0xfe, 0x03, 0x01}; /* az magic header */
103 
104 /* gzip flag uchar */
105 #define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
106 #define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
107 #define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
108 #define ORIG_NAME 0x08 /* bit 3 set: original file name present */
109 #define COMMENT 0x10 /* bit 4 set: file comment present */
110 #define RESERVED 0xE0 /* bits 5..7: reserved */
111 
112 #define AZ_MEMLEVEL 8
113 
114 static int ndbz_open(ndbzio_stream *s, const char *path, int Flags, File fd);
115 static int do_flush(ndbzio_stream *file, int flush);
116 static int get_byte(ndbzio_stream *s);
117 static unsigned char* get_block(ndbzio_stream *s, int blksz);
118 static int check_header(ndbzio_stream *s);
119 static int write_header(ndbzio_stream *s);
120 static int destroy(ndbzio_stream *s);
121 static void putLong(ndbzio_stream *s, uLong x);
122 static uLong getLong(ndbzio_stream *s);
123 static void read_header(ndbzio_stream *s, unsigned char *buffer);
124 
125 size_t ndbz_inflate_mem_size()
126 {
127  return sizeof(struct inflate_state) /* state */
128  + ((1U << MAX_WBITS)*sizeof(unsigned char)); /* window */
129 }
130 
131 size_t ndbz_deflate_mem_size()
132 {
133  return sizeof(deflate_state)
134  + ((1U << MAX_WBITS)*(2*sizeof(Byte))) /* window = wsize,2*|Byte| */
135  + ((1U << MAX_WBITS)*sizeof(Pos)) /* prev = wsize,|Pos| */
136  + ((1U << (AZ_MEMLEVEL+7))*sizeof(Pos)) /* head = hashsize,|Pos| */
137  + ((1U << (AZ_MEMLEVEL+6))*(sizeof(ush)+2));/* overlay= lit_bufsize,|ush|+2
138  */
139 }
140 
141 voidpf ndbz_alloc(voidpf opaque, uInt items, uInt size)
142 {
143  void * retval;
144  struct ndbz_alloc_rec *r = (struct ndbz_alloc_rec*)opaque;
145 
146  if((items * size) > r->mfree || r->mfree==0)
147  abort();
148 
149  assert(r->mfree <= r->size);
150 
151  retval= (r->mem + r->size) - r->mfree;
152  memset(retval, 0, items*size);
153  VALGRIND_MAKE_MEM_DEFINED(retval,items*size);
154  r->mfree -= items*size;
155 
156  return retval;
157 }
158 void ndbz_free(voidpf opaque, voidpf address)
159 {
160  struct ndbz_alloc_rec *r;
161  (void)address;
162  /* Oh how we hack. */
163  r = (struct ndbz_alloc_rec*)opaque;
164  r->mfree= r->size;
165  if(r->mfree==r->size)
166  VALGRIND_MAKE_MEM_NOACCESS(r->mem,r->size);
167 }
168 
169 #ifdef _WIN32
170 #ifndef ENOTSUP
171 /* If Windows doesn't define ENOTSUP, define it same as Solaris */
172 #define ENOTSUP 48
173 #endif
174 #endif
175 
176 #ifndef HAVE_POSIX_MEMALIGN
177 static inline int posix_memalign(void **memptr, size_t alignment, size_t size)
178 {
179 #ifdef HAVE_MEMALIGN
180  /* Solaris 10 has memalign but not posix_memalign */
181  *memptr = memalign(alignment,size);
182  if(!*memptr)
183  return ENOMEM;
184  return 0;
185 #else
186  /* But Darwin 7.9.0 doesn't have posix_memalign OR memalign */
187  (void)memptr;
188  (void)alignment;
189  (void)size;
190  return ENOTSUP; /* POSIX says we can return EINVAL or ENOMEM...
191  but we cheat here and do ENOTSUP so that code
192  elsewhere can work out if it can fall back to
193  plain malloc() or not as we cannot reasonably do aligned
194  memory allocation and free without leaking memory
195  */
196 #endif
197 }
198 #endif
199 
200 #define AZ_BUFSIZE_READ 32768
201 #define AZ_BUFSIZE_WRITE 16384
202 
203 size_t ndbz_bufsize_read(void)
204 {
205  return AZ_BUFSIZE_READ;
206 }
207 
208 size_t ndbz_bufsize_write(void)
209 {
210  return AZ_BUFSIZE_WRITE;
211 }
212 
213 /* ===========================================================================
214  Opens a gzip (.gz) file for reading or writing. The mode parameter
215  is as in fopen ("rb" or "wb"). The file is given either by file descriptor
216  or path name (if fd == -1).
217  ndbz_open returns NULL if the file could not be opened or if there was
218  insufficient memory to allocate the (de)compression state; errno
219  can be checked to distinguish the two cases (if errno is zero, the
220  zlib error is Z_MEM_ERROR).
221 
222  IO errors in my_errno.
223 
224  NOTE: If called without a fd, my_open *WILL* malloc()
225 */
226 int ndbz_open (ndbzio_stream *s, const char *path, int Flags, File fd)
227 {
228  int err;
229  int level = Z_DEFAULT_COMPRESSION; /* compression level */
230  int strategy = Z_DEFAULT_STRATEGY; /* compression strategy */
231 
232  if(s->stream.opaque)
233  {
234  s->stream.zalloc = (alloc_func)ndbz_alloc;
235  s->stream.zfree = (free_func)ndbz_free;
236  }
237  s->bufalloced = 0;
238  if(!s->inbuf)
239  {
240  err= posix_memalign((void**)&(s->inbuf),512,AZ_BUFSIZE_READ);
241  if(err==ENOTSUP)
242  s->inbuf= malloc(AZ_BUFSIZE_READ);
243  else if(err)
244  return -err;
245  err= posix_memalign((void**)&(s->outbuf),512,AZ_BUFSIZE_WRITE);
246  if(err==ENOTSUP)
247  s->outbuf= malloc(AZ_BUFSIZE_WRITE);
248  else if(err)
249  return -err;
250  s->bufalloced = 1;
251  }
252  memset(s->inbuf, 0, AZ_BUFSIZE_READ);
253  memset(s->outbuf, 0, AZ_BUFSIZE_WRITE);
254  s->stream.next_in = s->inbuf;
255  s->stream.next_out = s->outbuf;
256  s->stream.avail_in = s->stream.avail_out = 0;
257  s->z_err = Z_OK;
258  s->z_eof = 0;
259  s->in = 0;
260  s->out = 0;
261  s->back = EOF;
262  s->crc = crc32(0L, Z_NULL, 0);
263  s->transparent = 0;
264  s->mode = 'r';
265  s->version = (unsigned char)az_magic[1]; /* this needs to be a define to version */
266  s->version = (unsigned char)az_magic[2]; /* minor version */
267 
268  /*
269  We do our own version of append by nature.
270  We must always have write access to take card of the header.
271  */
272  assert(Flags | O_APPEND);
273  assert(Flags | O_WRONLY);
274 
275  if (Flags & O_RDWR || Flags & O_WRONLY)
276  s->mode = 'w';
277 
278  if (s->mode == 'w')
279  {
280  err = deflateInit2(&(s->stream), level,
281  Z_DEFLATED, -MAX_WBITS, AZ_MEMLEVEL, strategy);
282  /* windowBits is passed < 0 to suppress zlib header */
283 
284  s->stream.next_out = s->outbuf;
285  if (err != Z_OK)
286  {
287  destroy(s);
288  return Z_NULL;
289  }
290  } else {
291  s->stream.next_in = s->inbuf;
292 
293  err = inflateInit2(&(s->stream), -MAX_WBITS);
294  /* windowBits is passed < 0 to tell that there is no zlib header.
295  * Note that in this case inflate *requires* an extra "dummy" byte
296  * after the compressed stream in order to complete decompression and
297  * return Z_STREAM_END. Here the gzip CRC32 ensures that 4 bytes are
298  * present after the compressed stream.
299  */
300  if (err != Z_OK)
301  {
302  destroy(s);
303  return Z_NULL;
304  }
305  }
306  s->stream.avail_out = AZ_BUFSIZE_WRITE;
307 
308  errno = 0;
309  s->file = fd < 0 ? my_open(path, Flags, MYF(0)) : fd;
310 
311  if (s->file < 0 )
312  {
313  destroy(s);
314  return Z_NULL;
315  }
316 
317  if (Flags & O_CREAT || Flags & O_TRUNC)
318  {
319  s->rows= 0;
320  s->forced_flushes= 0;
321  s->shortest_row= 0;
322  s->longest_row= 0;
323  s->auto_increment= 0;
324  s->check_point= 0;
325  s->comment_start_pos= 0;
326  s->comment_length= 0;
327  s->frm_start_pos= 0;
328  s->frm_length= 0;
329  s->dirty= 1; /* We create the file dirty */
330  s->start = AZHEADER_SIZE + AZMETA_BUFFER_SIZE;
331  if(write_header(s))
332  return Z_NULL;
333  if(my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
334  return Z_NULL;
335  }
336  else if (s->mode == 'w')
337  {
338  if(my_pread(s->file, s->inbuf, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
339  MYF(0)) < AZHEADER_SIZE + AZMETA_BUFFER_SIZE)
340  return Z_NULL;
341  read_header(s, s->inbuf); /* skip the .az header */
342  if(my_seek(s->file, 0, MY_SEEK_END, MYF(0)) == MY_FILEPOS_ERROR)
343  return Z_NULL;
344  }
345  else
346  {
347  if(check_header(s)!=0) /* skip the .az header */
348  return Z_NULL;
349  }
350 
351  return 1;
352 }
353 
354 
355 int write_header(ndbzio_stream *s)
356 {
357  char *buffer= (char*)s->outbuf;
358  char *ptr= buffer;
359 
360  s->block_size= AZ_BUFSIZE_WRITE;
361  s->version = (unsigned char)az_magic[1];
362  s->minor_version = (unsigned char)az_magic[2];
363 
364 
365  /* Write a very simple .az header: */
366  memset(buffer, 0, AZHEADER_SIZE + AZMETA_BUFFER_SIZE);
367  *(ptr + AZ_MAGIC_POS)= az_magic[0];
368  *(ptr + AZ_VERSION_POS)= (unsigned char)s->version;
369  *(ptr + AZ_MINOR_VERSION_POS)= (unsigned char)s->minor_version;
370  *(ptr + AZ_BLOCK_POS)= (unsigned char)(s->block_size/1024); /* Reserved for block size */
371  *(ptr + AZ_STRATEGY_POS)= (unsigned char)Z_DEFAULT_STRATEGY; /* Compression Type */
372 
373  int4store(ptr + AZ_FRM_POS, s->frm_start_pos); /* FRM Block */
374  int4store(ptr + AZ_FRM_LENGTH_POS, s->frm_length); /* FRM Block */
375  int4store(ptr + AZ_COMMENT_POS, s->comment_start_pos); /* COMMENT Block */
376  int4store(ptr + AZ_COMMENT_LENGTH_POS, s->comment_length); /* COMMENT Block */
377  int4store(ptr + AZ_META_POS, 0); /* Meta Block */
378  int4store(ptr + AZ_META_LENGTH_POS, 0); /* Meta Block */
379  int8store(ptr + AZ_START_POS, (unsigned long long)s->start); /* Start of Data Block Index Block */
380  int8store(ptr + AZ_ROW_POS, (unsigned long long)s->rows); /* Start of Data Block Index Block */
381  int8store(ptr + AZ_FLUSH_POS, (unsigned long long)s->forced_flushes); /* Start of Data Block Index Block */
382  int8store(ptr + AZ_CHECK_POS, (unsigned long long)s->check_point); /* Start of Data Block Index Block */
383  int8store(ptr + AZ_AUTOINCREMENT_POS, (unsigned long long)s->auto_increment); /* Start of Data Block Index Block */
384  int4store(ptr+ AZ_LONGEST_POS , s->longest_row); /* Longest row */
385  int4store(ptr+ AZ_SHORTEST_POS, s->shortest_row); /* Shorest row */
386  int4store(ptr+ AZ_FRM_POS,
387  AZHEADER_SIZE + AZMETA_BUFFER_SIZE); /* FRM position */
388  *(ptr + AZ_DIRTY_POS)= (unsigned char)s->dirty; /* Start of Data Block Index Block */
389 
390  /* Always begin at the begining, and end there as well */
391  if(my_pwrite(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
392  MYF(0)) == (size_t)-1)
393  return -1;
394 
395  return 0;
396 }
397 
398 /* ===========================================================================
399  Opens a gzip (.gz) file for reading or writing.
400 */
401 int ndbzopen(ndbzio_stream *s, const char *path, int Flags)
402 {
403  return ndbz_open(s, path, Flags, -1);
404 }
405 
406 /* ===========================================================================
407  Associate a gzFile with the file descriptor fd. fd is not dup'ed here
408  to mimic the behavio(u)r of fdopen.
409 */
410 int ndbzdopen(ndbzio_stream *s, File fd, int Flags)
411 {
412  if (fd < 0) return 0;
413 
414  return ndbz_open (s, NULL, Flags, fd);
415 }
416 
417 /*
418  Read from ndbzio_stream into buffer.
419  Reads up to AZ_BUFSIZE_READ bytes.
420 
421  Number of Bytes read is in: s->stream.avail_in
422 
423  return 0 on success
424  */
425 int read_buffer(ndbzio_stream *s)
426 {
427  if (s->z_eof) return EOF;
428  my_errno= 0;
429  if (s->stream.avail_in == 0)
430  {
431  s->stream.avail_in = my_read(s->file, (uchar *)s->inbuf, AZ_BUFSIZE_READ, MYF(0));
432  if(s->stream.avail_in > 0)
433  my_errno= 0;
434  if (s->stream.avail_in == 0)
435  {
436  s->z_eof = 1;
437  }
438  s->stream.next_in = s->inbuf;
439  }
440  return my_errno;
441 }
442 
443 /*
444  Read a byte from a ndbzio_stream; update next_in and avail_in.
445 
446  returns EOF on error;
447 */
448 int get_byte(ndbzio_stream *s)
449 {
450  if (s->stream.avail_in == 0)
451  if(read_buffer(s))
452  return EOF;
453  s->stream.avail_in--;
454  return *(s->stream.next_in)++;
455 }
456 
457 /*
458  * Gets block of size blksz
459  * *MUST* be < buffer size
460  * *MUST* be aligned to IO size (i.e. not be only partially in buffer)
461  */
462 unsigned char* get_block(ndbzio_stream *s,int blksz)
463 {
464  unsigned char *r= s->stream.next_in;
465  if (s->stream.avail_in == 0)
466  if(read_buffer(s))
467  return NULL;
468  s->stream.avail_in-=blksz;
469  s->stream.next_in+=blksz;
470 
471  return r;
472 }
473 
474 /* ===========================================================================
475  Check the gzip header of a ndbzio_stream opened for reading. Set the stream
476  mode to transparent if the gzip magic header is not present; set s->err
477  to Z_DATA_ERROR if the magic header is present but the rest of the header
478  is incorrect.
479  IN assertion: the stream s has already been created sucessfully;
480  s->stream.avail_in is zero for the first time, but may be non-zero
481  for concatenated .gz files.
482 */
483 int check_header(ndbzio_stream *s)
484 {
485  int method; /* method uchar */
486  int flags; /* flags uchar */
487  uInt len;
488  int c;
489 
490  if(s->stream.avail_in==0)
491  if((c= read_buffer(s)))
492  return 0;
493 
494  /* Peek ahead to check the gzip magic header */
495  if ( s->stream.next_in[0] == gz_magic[0] && s->stream.next_in[1] == gz_magic[1])
496  {
497  abort(); /* FIXME: stewart broke it, massively */
498  s->stream.avail_in -= 2;
499  s->stream.next_in += 2;
500  s->version= (unsigned char)2;
501 
502  /* Check the rest of the gzip header */
503  method = get_byte(s);
504  flags = get_byte(s);
505  if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
506  s->z_err = Z_DATA_ERROR;
507  return 0;
508  }
509 
510  /* Discard time, xflags and OS code: */
511  for (len = 0; len < 6; len++) (void)get_byte(s);
512 
513  if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */
514  len = (uInt)get_byte(s);
515  len += ((uInt)get_byte(s))<<8;
516  /* len is garbage if EOF but the loop below will quit anyway */
517  while (len-- != 0 && get_byte(s) != EOF) ;
518  }
519  if ((flags & ORIG_NAME) != 0) { /* skip the original file name */
520  while ((c = get_byte(s)) != 0 && c != EOF) ;
521  }
522  if ((flags & COMMENT) != 0) { /* skip the .gz file comment */
523  while ((c = get_byte(s)) != 0 && c != EOF) ;
524  }
525  if ((flags & HEAD_CRC) != 0) { /* skip the header crc */
526  for (len = 0; len < 2; len++) (void)get_byte(s);
527  }
528  s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK;
529  s->start = my_tell(s->file, MYF(0));
530  if(s->start == (my_off_t)-1)
531  return my_errno;
532  s->start-= s->stream.avail_in;
533  }
534  else if ( s->stream.next_in[0] == az_magic[0]
535  && s->stream.next_in[1] == az_magic[1])
536  {
537  unsigned char *header_block;
538  if(s->stream.avail_in < AZHEADER_SIZE + AZMETA_BUFFER_SIZE)
539  {
540  s->z_err = Z_DATA_ERROR;
541  return s->z_err;
542  }
543  header_block = get_block(s,512);
544  if(!header_block)
545  return my_errno;
546  read_header(s, header_block);
547  }
548  else
549  {
550  s->transparent = 1;
551  ndbzseek(s,0,SEEK_SET);
552  s->z_err = Z_OK;
553 
554  return 0;
555  }
556 
557  return 0;
558 }
559 
560 void read_header(ndbzio_stream *s, unsigned char *buffer)
561 {
562  if (buffer[0] == az_magic[0] && buffer[1] == az_magic[1])
563  {
564  s->version= (unsigned int)buffer[AZ_VERSION_POS];
565  s->minor_version= (unsigned int)buffer[AZ_MINOR_VERSION_POS];
566  s->block_size= 1024 * buffer[AZ_BLOCK_POS];
567  s->start= (unsigned long long)uint8korr(buffer + AZ_START_POS);
568  s->rows= (unsigned long long)uint8korr(buffer + AZ_ROW_POS);
569  s->check_point= (unsigned long long)uint8korr(buffer + AZ_CHECK_POS);
570  s->forced_flushes= (unsigned long long)uint8korr(buffer + AZ_FLUSH_POS);
571  s->auto_increment= (unsigned long long)uint8korr(buffer + AZ_AUTOINCREMENT_POS);
572  s->longest_row= (unsigned int)uint4korr(buffer + AZ_LONGEST_POS);
573  s->shortest_row= (unsigned int)uint4korr(buffer + AZ_SHORTEST_POS);
574  s->frm_start_pos= (unsigned int)uint4korr(buffer + AZ_FRM_POS);
575  s->frm_length= (unsigned int)uint4korr(buffer + AZ_FRM_LENGTH_POS);
576  s->comment_start_pos= (unsigned int)uint4korr(buffer + AZ_COMMENT_POS);
577  s->comment_length= (unsigned int)uint4korr(buffer + AZ_COMMENT_LENGTH_POS);
578  s->dirty= (unsigned int)buffer[AZ_DIRTY_POS];
579  }
580  else
581  {
582  assert(buffer[0] == az_magic[0] && buffer[1] == az_magic[1]);
583  return;
584  }
585 }
586 
587 /* ===========================================================================
588  * Cleanup then free the given ndbzio_stream. Return a zlib error code.
589  Try freeing in the reverse order of allocations.
590  */
591 int destroy (ndbzio_stream *s)
592 {
593  int err = Z_OK;
594 
595  if (s->stream.state != NULL)
596  {
597  if (s->mode == 'w')
598  err = deflateEnd(&(s->stream));
599  else if (s->mode == 'r')
600  err = inflateEnd(&(s->stream));
601  }
602 
603  if (s->file > 0 && my_close(s->file, MYF(0)))
604  err = Z_ERRNO;
605 
606  s->file= -1;
607 
608  if (s->z_err < 0) err = s->z_err;
609 
610  if(s->bufalloced)
611  {
612  free(s->inbuf);
613  free(s->outbuf);
614  }
615 
616  return err;
617 }
618 
619 /* ===========================================================================
620  Reads the given number of uncompressed bytes from the compressed file.
621  ndbzread returns the number of bytes actually read (0 for end of file).
622 */
623 unsigned int ZEXPORT ndbzread ( ndbzio_stream *s, voidp buf, unsigned int len, int *error)
624 {
625  Bytef *start = (Bytef*)buf; /* starting point for crc computation */
626  Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */
627  *error= 0;
628 
629  if (s->mode != 'r')
630  {
631  *error= Z_STREAM_ERROR;
632  return 0;
633  }
634 
635  if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO)
636  {
637  *error= s->z_err;
638  return 0;
639  }
640 
641  if (s->z_err == Z_STREAM_END) /* EOF */
642  {
643  return 0;
644  }
645 
646  next_out = (Byte*)buf;
647  s->stream.next_out = (Bytef*)buf;
648  s->stream.avail_out = len;
649 
650  if (s->stream.avail_out && s->back != EOF) {
651  *next_out++ = s->back;
652  s->stream.next_out++;
653  s->stream.avail_out--;
654  s->back = EOF;
655  s->out++;
656  start++;
657  if (s->last) {
658  s->z_err = Z_STREAM_END;
659  {
660  return 1;
661  }
662  }
663  }
664  while (s->stream.avail_out != 0) {
665 
666  if (s->transparent) {
667  /* Copy first the lookahead bytes: */
668  uInt n = s->stream.avail_in;
669  if (n > s->stream.avail_out) n = s->stream.avail_out;
670  if (n > 0) {
671  memcpy(s->stream.next_out, s->stream.next_in, n);
672  next_out += n;
673  s->stream.next_out = (Bytef *)next_out;
674  s->stream.next_in += n;
675  s->stream.avail_out -= n;
676  s->stream.avail_in -= n;
677  }
678  if (s->stream.avail_out > 0)
679  {
680  size_t bytes_read;
681  bytes_read= my_read(s->file, (uchar *)next_out, s->stream.avail_out,
682  MYF(0));
683  if(bytes_read>0)
684  s->stream.avail_out -= bytes_read;
685  if (bytes_read == 0)
686  {
687  s->z_eof = 1;
688  return 0;
689  }
690  }
691  len -= s->stream.avail_out;
692  s->in += len;
693  s->out += len;
694  return len;
695  }
696 
697 
698  if (s->stream.avail_in == 0 && !s->z_eof) {
699  read_buffer(s);
700  if (s->stream.avail_in == 0)
701  {
702  s->z_eof = 1;
703  }
704  }
705  s->in += s->stream.avail_in;
706  s->out += s->stream.avail_out;
707  s->z_err = inflate(&(s->stream), Z_NO_FLUSH);
708  s->in -= s->stream.avail_in;
709  s->out -= s->stream.avail_out;
710 
711  if (s->z_err == Z_STREAM_END) {
712  /* Check CRC and original size */
713  uInt gotcrc;
714  s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
715  start = s->stream.next_out;
716 
717  gotcrc = getLong(s);
718  if (gotcrc != s->crc) {
719  s->z_err = Z_DATA_ERROR;
720  } else {
721  (void)getLong(s);
722  /* The uncompressed length returned by above getlong() may be
723  * different from s->out in case of concatenated .gz files.
724  * Check for such files:
725  *//*
726  check_header(s);
727  if (s->z_err == Z_OK)
728  {
729  inflateReset(&(s->stream));
730  s->crc = crc32(0L, Z_NULL, 0);
731  }*/
732  }
733  }
734  if (s->z_err != Z_OK || s->z_eof) break;
735  }
736  s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start));
737 
738  if (len == s->stream.avail_out &&
739  (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO))
740  {
741  *error= s->z_err;
742  return 0;
743  }
744 
745  return (len - s->stream.avail_out);
746 }
747 
748 /*
749  Write last remaining 512 byte block of write buffer, 0 padded.
750  */
751 int flush_write_buffer(ndbzio_stream *s)
752 {
753  uInt real_len = AZ_BUFSIZE_WRITE - s->stream.avail_out;
754  uInt len = ((real_len+0x1FF)>>9)<<9;
755 
756  memset(s->outbuf+real_len, 0, s->stream.avail_out);
757 
758  s->check_point= my_tell(s->file, MYF(0));
759 
760  my_write(s->file,(uchar*)s->outbuf,len,MYF(0));
761 
762  s->dirty= AZ_STATE_CLEAN;
763 
764  return 0;
765 }
766 
767 int write_buffer(ndbzio_stream *s)
768 {
769  if (s->stream.avail_out == 0)
770  {
771  s->stream.next_out = s->outbuf;
772  if (my_write(s->file, (uchar *)s->outbuf, AZ_BUFSIZE_WRITE,
773  MYF(0)) != AZ_BUFSIZE_WRITE)
774  {
775  s->z_err = Z_ERRNO;
776  return my_errno;
777  }
778  s->stream.avail_out = AZ_BUFSIZE_WRITE;
779  }
780  return 0;
781 }
782 
783 /* ===========================================================================
784  Writes the given number of uncompressed bytes into the compressed file.
785  ndbzwrite returns the number of bytes actually written (0 in case of error).
786 */
787 unsigned int ndbzwrite (ndbzio_stream *s, const void* buf, unsigned int len)
788 {
789  unsigned int i;
790  s->stream.next_in = (Bytef*)buf;
791  s->stream.avail_in = len;
792 
793  s->rows++;
794 
795  for(i=0;i<len;i++)
796  memcmp(buf,s,1);
797 
798  while (s->stream.avail_in != 0)
799  {
800  if(write_buffer(s))
801  return 0;
802  s->in += s->stream.avail_in;
803  s->out += s->stream.avail_out;
804  s->z_err = deflate(&(s->stream), Z_NO_FLUSH);
805  s->in -= s->stream.avail_in;
806  s->out -= s->stream.avail_out;
807  if (s->z_err != Z_OK) break;
808  }
809  s->crc = crc32(s->crc, (const Bytef *)buf, len);
810 
811  if (len > s->longest_row)
812  s->longest_row= len;
813 
814  if (len < s->shortest_row || !(s->shortest_row))
815  s->shortest_row= len;
816 
817  return (unsigned int)(len - s->stream.avail_in);
818 }
819 
820 
821 /* ===========================================================================
822  Flushes all pending output into the compressed file. The parameter
823  flush is as in the deflate() function.
824 */
825 int do_flush (ndbzio_stream *s, int flush)
826 {
827  uInt len;
828  int done = 0;
829 
830  if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR;
831 
832  s->stream.avail_in = 0; /* should be zero already anyway */
833 
834  for (;;)
835  {
836  len = AZ_BUFSIZE_WRITE - s->stream.avail_out;
837  write_buffer(s);
838 
839  if (done) break;
840  s->out += s->stream.avail_out;
841  s->z_err = deflate(&(s->stream), flush);
842  s->out -= s->stream.avail_out;
843 
844  /* Ignore the second of two consecutive flushes: */
845  if (len == 0 && s->z_err == Z_BUF_ERROR) s->z_err = Z_OK;
846 
847  /* deflate has finished flushing only when it hasn't used up
848  * all the available space in the output buffer:
849  */
850  done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END);
851 
852  if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break;
853  }
854 
855  if (flush == Z_FINISH)
856  s->dirty= AZ_STATE_CLEAN; /* Mark it clean, we should be good now */
857  else
858  s->dirty= AZ_STATE_SAVED; /* Mark it clean, we should be good now */
859 
860  return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
861 }
862 
863 int ZEXPORT ndbzflush (ndbzio_stream *s, int flush)
864 {
865  int err;
866 
867  if (s->mode == 'r')
868  {
869  unsigned char buffer[AZHEADER_SIZE + AZMETA_BUFFER_SIZE];
870  if(my_pread(s->file, (uchar*) buffer, AZHEADER_SIZE + AZMETA_BUFFER_SIZE, 0,
871  MYF(0)) == (size_t)-1)
872  return Z_ERRNO;
873  read_header(s, buffer); /* skip the .az header */
874 
875  return Z_OK;
876  }
877  else
878  {
879  s->forced_flushes++;
880  err= do_flush(s, flush);
881 
882  if (err) return err;
883  if(my_sync(s->file, MYF(0)) == -1)
884  return Z_ERRNO;
885  return s->z_err == Z_STREAM_END ? Z_OK : s->z_err;
886  }
887 }
888 
889 /* ===========================================================================
890  Rewinds input file.
891 */
892 int ndbzrewind (ndbzio_stream *s)
893 {
894  if (s == NULL || s->mode != 'r') return -1;
895 
896  s->z_err = Z_OK;
897  s->z_eof = 0;
898  s->back = EOF;
899  s->stream.avail_in = 0;
900  s->stream.next_in = (Bytef *)s->inbuf;
901  s->crc = crc32(0L, Z_NULL, 0);
902  if (!s->transparent) (void)inflateReset(&s->stream);
903  s->in = 0;
904  s->out = 0;
905  return my_seek(s->file, (int)s->start, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR;
906 }
907 
908 /* ===========================================================================
909  Sets the starting position for the next ndbzread or ndbzwrite on the given
910  compressed file. The offset represents a number of bytes in the
911  ndbzseek returns the resulting offset location as measured in bytes from
912  the beginning of the uncompressed stream, or -1 in case of error.
913  SEEK_END is not implemented, returns error.
914  In this version of the library, ndbzseek can be extremely slow.
915 */
916 my_off_t ndbzseek (ndbzio_stream *s, my_off_t offset, int whence)
917 {
918 
919  if (s == NULL || whence == SEEK_END ||
920  s->z_err == Z_ERRNO || s->z_err == Z_DATA_ERROR) {
921  return -1L;
922  }
923 
924  if (s->mode == 'w')
925  {
926  if (whence == SEEK_SET)
927  offset -= s->in;
928 
929  /* At this point, offset is the number of zero bytes to write. */
930  /* There was a zmemzero here if inbuf was null -Brian */
931  while (offset > 0)
932  {
933  uInt size = AZ_BUFSIZE_WRITE;
934  if (offset < AZ_BUFSIZE_WRITE) size = (uInt)offset;
935 
936  size = ndbzwrite(s, s->inbuf, size);
937  if (size == 0) return -1L;
938 
939  offset -= size;
940  }
941  return s->in;
942  }
943  /* Rest of function is for reading only */
944 
945  /* compute absolute position */
946  if (whence == SEEK_CUR) {
947  offset += s->out;
948  }
949 
950  if (s->transparent) {
951  /* map to my_seek */
952  s->back = EOF;
953  s->stream.avail_in = 0;
954  s->stream.next_in = (Bytef *)s->inbuf;
955  if (my_seek(s->file, offset, MY_SEEK_SET, MYF(0)) == MY_FILEPOS_ERROR) return -1L;
956 
957  s->in = s->out = offset;
958  return offset;
959  }
960 
961  /* For a negative seek, rewind and use positive seek */
962  if (offset >= s->out) {
963  offset -= s->out;
964  } else if (ndbzrewind(s)) {
965  return -1L;
966  }
967  /* offset is now the number of bytes to skip. */
968 
969  if (offset && s->back != EOF) {
970  s->back = EOF;
971  s->out++;
972  offset--;
973  if (s->last) s->z_err = Z_STREAM_END;
974  }
975  while (offset > 0) {
976  int error;
977  unsigned int size = AZ_BUFSIZE_READ;
978  if (offset < AZ_BUFSIZE_READ) size = (int)offset;
979 
980  size = ndbzread(s, s->outbuf, size, &error);
981  if (error <= 0) return -1L;
982  offset -= size;
983  }
984  return s->out;
985 }
986 
987 /* ===========================================================================
988  Returns the starting position for the next ndbzread or ndbzwrite on the
989  given compressed file. This position represents a number of bytes in the
990  uncompressed data stream.
991 */
992 my_off_t ZEXPORT ndbztell (ndbzio_stream *file)
993 {
994  return ndbzseek(file, 0L, SEEK_CUR);
995 }
996 
997 
998 /* ===========================================================================
999  Outputs a long in LSB order to the given ndbzio_stream
1000 */
1001 void putLong (ndbzio_stream *s, uLong x)
1002 {
1003  int n;
1004 
1005  for (n = 0; n < 4; n++)
1006  {
1007  s->stream.avail_out--;
1008  *(s->stream.next_out) = (Bytef)(x & 0xff);
1009  s->stream.next_out++;
1010  write_buffer(s);
1011  x >>= 8;
1012  }
1013 }
1014 
1015 /* ===========================================================================
1016  Reads a long in LSB order from the given ndbzio_stream. Sets z_err in case
1017  of error.
1018 */
1019 uLong getLong (ndbzio_stream *s)
1020 {
1021  uLong x = (uLong)get_byte(s);
1022  int c;
1023 
1024  x += ((uLong)get_byte(s))<<8;
1025  x += ((uLong)get_byte(s))<<16;
1026  c = get_byte(s);
1027  if (c == EOF) s->z_err = Z_DATA_ERROR;
1028  x += ((uLong)c)<<24;
1029  return x;
1030 }
1031 
1032 /* ===========================================================================
1033  Flushes all pending output if necessary, closes the compressed file
1034  and deallocates all the (de)compression state.
1035 */
1036 int ndbzclose (ndbzio_stream *s)
1037 {
1038 
1039  if (s == NULL) return Z_STREAM_ERROR;
1040 
1041  if (s->file < 1) return Z_OK;
1042 
1043  if (s->mode == 'w')
1044  {
1045  int r= do_flush(s, Z_FINISH);
1046  if(r!= Z_OK)
1047  {
1048  return destroy(s);
1049  }
1050 
1051  putLong(s, s->crc);
1052  putLong(s, (uLong)(s->in & 0xffffffff));
1053  putLong(s, 0x4E444244);
1054 
1055  flush_write_buffer(s);
1056  }
1057 
1058  return destroy(s);
1059 }
1060 
1061 #include <my_dir.h> // MY_STAT, my_fstat
1062 
1063 int ndbz_file_size(ndbzio_stream *s, size_t *size)
1064 {
1065  MY_STAT stat_buf;
1066 
1067  if (s == NULL || size == NULL)
1068  return -1;
1069 
1070  if (my_fstat(s->file, &stat_buf, 0) != 0)
1071  return -1;
1072 
1073  *size = stat_buf.st_size;
1074  return 0; /* OK */
1075 }