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