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