]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/file.c
Merge changes from CUPS 1.3.1.
[thirdparty/cups.git] / cups / file.c
CommitLineData
ef416fc2 1/*
bc44d920 2 * "$Id: file.c 6649 2007-07-11 21:46:42Z mike $"
ef416fc2 3 *
4 * File functions for the Common UNIX Printing System (CUPS).
5 *
6 * Since stdio files max out at 256 files on many systems, we have to
7 * write similar functions without this limit. At the same time, using
8 * our own file functions allows us to provide transparent support of
9 * gzip'd print files, PPD files, etc.
10 *
bc44d920 11 * Copyright 2007 by Apple Inc.
b86bc4cf 12 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 13 *
14 * These coded instructions, statements, and computer programs are the
bc44d920 15 * property of Apple Inc. and are protected by Federal copyright
16 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
17 * which should have been included with this file. If this file is
18 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 19 *
20 * Contents:
21 *
22 * cupsFileClose() - Close a CUPS file.
23 * cupsFileCompression() - Return whether a file is compressed.
24 * cupsFileEOF() - Return the end-of-file status.
fa73b229 25 * cupsFileFind() - Find a file using the specified path.
ef416fc2 26 * cupsFileFlush() - Flush pending output.
27 * cupsFileGetChar() - Get a single character from a file.
28 * cupsFileGetConf() - Get a line from a configuration file...
80ca4592 29 * cupsFileGetLine() - Get a CR and/or LF-terminated line that may
30 * contain binary data.
ef416fc2 31 * cupsFileGets() - Get a CR and/or LF-terminated line.
32 * cupsFileLock() - Temporarily lock access to a file.
80ca4592 33 * cupsFileNumber() - Return the file descriptor associated with a CUPS
34 * file.
ef416fc2 35 * cupsFileOpen() - Open a CUPS file.
36 * cupsFileOpenFd() - Open a CUPS file using a file descriptor.
37 * cupsFilePeekChar() - Peek at the next character from a file.
38 * cupsFilePrintf() - Write a formatted string.
39 * cupsFilePutChar() - Write a character.
40 * cupsFilePuts() - Write a string.
41 * cupsFileRead() - Read from a file.
42 * cupsFileRewind() - Rewind a file.
43 * cupsFileSeek() - Seek in a file.
80ca4592 44 * cupsFileStderr() - Return a CUPS file associated with stderr.
45 * cupsFileStdin() - Return a CUPS file associated with stdin.
46 * cupsFileStdout() - Return a CUPS file associated with stdout.
ef416fc2 47 * cupsFileTell() - Return the current file position.
48 * cupsFileUnlock() - Unlock access to a file.
49 * cupsFileWrite() - Write to a file.
50 * cups_compress() - Compress a buffer of data...
51 * cups_fill() - Fill the input buffer...
52 * cups_read() - Read from a file descriptor.
53 * cups_write() - Write to a file descriptor.
54 */
55
56/*
57 * Include necessary headers...
58 */
59
60#include <stdio.h>
61#include <stdlib.h>
62#include <stdarg.h>
ef416fc2 63#include <errno.h>
ef416fc2 64#include <sys/types.h>
65#include <fcntl.h>
80ca4592 66#include "http-private.h"
67#include "globals.h"
68#include "debug.h"
ef416fc2 69
ef416fc2 70#ifdef HAVE_LIBZ
71# include <zlib.h>
72#endif /* HAVE_LIBZ */
73#ifdef WIN32
74# include <io.h>
75# include <sys/locking.h>
76#endif /* WIN32 */
77
78
79/*
80 * Some operating systems support large files via open flag O_LARGEFILE...
81 */
82
83#ifndef O_LARGEFILE
84# define O_LARGEFILE 0
85#endif /* !O_LARGEFILE */
86
87
b86bc4cf 88/*
89 * Some operating systems don't define O_BINARY, which is used by Microsoft
90 * and IBM to flag binary files...
91 */
92
93#ifndef O_BINARY
94# define O_BINARY 0
95#endif /* !O_BINARY */
96
97
ef416fc2 98/*
99 * Types and structures...
100 */
101
102struct _cups_file_s /**** CUPS file structure... ****/
103
104{
105 int fd; /* File descriptor */
106 char mode, /* Mode ('r' or 'w') */
107 compressed, /* Compression used? */
80ca4592 108 is_stdio, /* stdin/out/err? */
ef416fc2 109 eof, /* End of file? */
fa73b229 110 buf[4096], /* Buffer */
ef416fc2 111 *ptr, /* Pointer into buffer */
112 *end; /* End of buffer data */
113 off_t pos; /* File position for start of buffer */
114
115#ifdef HAVE_LIBZ
116 z_stream stream; /* (De)compression stream */
fa73b229 117 Bytef cbuf[4096]; /* (De)compression buffer */
ef416fc2 118 uLong crc; /* (De)compression CRC */
119#endif /* HAVE_LIBZ */
120};
121
122
123/*
124 * Local functions...
125 */
126
127#ifdef HAVE_LIBZ
128static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
129#endif /* HAVE_LIBZ */
130static ssize_t cups_fill(cups_file_t *fp);
131static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
132static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
133
134
135/*
136 * 'cupsFileClose()' - Close a CUPS file.
137 */
138
139int /* O - 0 on success, -1 on error */
140cupsFileClose(cups_file_t *fp) /* I - CUPS file */
141{
142 int fd; /* File descriptor */
143 char mode; /* Open mode */
144 int status; /* Return status */
80ca4592 145 int is_stdio; /* Is a stdio file? */
ef416fc2 146
147
148 DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
149
150 /*
151 * Range check...
152 */
153
154 if (!fp)
155 return (-1);
156
157 /*
158 * Flush pending write data...
159 */
160
161 if (fp->mode == 'w')
162 status = cupsFileFlush(fp);
163 else
164 status = 0;
165
166#ifdef HAVE_LIBZ
167 if (fp->compressed && status >= 0)
168 {
169 if (fp->mode == 'r')
170 {
171 /*
172 * Free decompression data...
173 */
174
175 inflateEnd(&fp->stream);
176 }
177 else
178 {
179 /*
180 * Flush any remaining compressed data...
181 */
182
183 unsigned char trailer[8]; /* Trailer CRC and length */
184 int done; /* Done writing... */
185
186
187 fp->stream.avail_in = 0;
188
189 for (done = 0;;)
190 {
191 if (fp->stream.next_out > fp->cbuf)
192 {
193 if (cups_write(fp, (char *)fp->cbuf,
194 fp->stream.next_out - fp->cbuf) < 0)
195 status = -1;
196
197 fp->stream.next_out = fp->cbuf;
198 fp->stream.avail_out = sizeof(fp->cbuf);
199 }
200
201 if (done || status < 0)
202 break;
203
204 done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
205 fp->stream.next_out == fp->cbuf;
206 }
207
208 /*
209 * Write the CRC and length...
210 */
211
212 trailer[0] = fp->crc;
213 trailer[1] = fp->crc >> 8;
214 trailer[2] = fp->crc >> 16;
215 trailer[3] = fp->crc >> 24;
216 trailer[4] = fp->pos;
217 trailer[5] = fp->pos >> 8;
218 trailer[6] = fp->pos >> 16;
219 trailer[7] = fp->pos >> 24;
220
221 if (cups_write(fp, (char *)trailer, 8) < 0)
222 status = -1;
223
224 /*
225 * Free all memory used by the compression stream...
226 */
227
228 deflateEnd(&(fp->stream));
229 }
230 }
231#endif /* HAVE_LIBZ */
232
233 /*
234 * Save the file descriptor we used and free memory...
235 */
236
80ca4592 237 fd = fp->fd;
238 mode = fp->mode;
239 is_stdio = fp->is_stdio;
ef416fc2 240
241 free(fp);
242
243 /*
244 * Close the file, returning the close status...
245 */
246
247 if (mode == 's')
248 {
249 if (closesocket(fd) < 0)
250 status = -1;
251 }
80ca4592 252 else if (!is_stdio)
ef416fc2 253 {
254 if (close(fd) < 0)
255 status = -1;
256 }
257
258 return (status);
259}
260
261
262/*
263 * 'cupsFileCompression()' - Return whether a file is compressed.
264 */
265
266int /* O - CUPS_FILE_NONE or CUPS_FILE_GZIP */
267cupsFileCompression(cups_file_t *fp) /* I - CUPS file */
268{
80ca4592 269 return (fp ? fp->compressed : CUPS_FILE_NONE);
ef416fc2 270}
271
272
273/*
274 * 'cupsFileEOF()' - Return the end-of-file status.
275 */
276
277int /* O - 1 on EOF, 0 otherwise */
278cupsFileEOF(cups_file_t *fp) /* I - CUPS file */
279{
80ca4592 280 return (fp ? fp->eof : 1);
ef416fc2 281}
282
283
fa73b229 284/*
285 * 'cupsFileFind()' - Find a file using the specified path.
286 *
287 * This function allows the paths in the path string to be separated by
288 * colons (UNIX standard) or semicolons (Windows standard) and stores the
289 * result in the buffer supplied. If the file cannot be found in any of
290 * the supplied paths, NULL is returned. A NULL path only matches the
291 * current directory.
292 */
293
294const char * /* O - Full path to file or NULL */
295cupsFileFind(const char *filename, /* I - File to find */
296 const char *path, /* I - Colon/semicolon-separated path */
4400e98d 297 int executable, /* I - 1 = executable files, 0 = any file/dir */
298 char *buffer, /* I - Filename buffer */
fa73b229 299 int bufsize) /* I - Size of filename buffer */
300{
301 char *bufptr, /* Current position in buffer */
302 *bufend; /* End of buffer */
303
304
305 /*
306 * Range check input...
307 */
308
309 if (!filename || !buffer || bufsize < 2)
310 return (NULL);
311
312 if (!path)
313 {
314 /*
315 * No path, so check current directory...
316 */
317
318 if (!access(filename, 0))
319 {
320 strlcpy(buffer, filename, bufsize);
321 return (buffer);
322 }
323 else
324 return (NULL);
325 }
326
327 /*
328 * Now check each path and return the first match...
329 */
330
331 bufend = buffer + bufsize - 1;
332 bufptr = buffer;
333
334 while (*path)
335 {
b86bc4cf 336#ifdef WIN32
337 if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
338#else
fa73b229 339 if (*path == ';' || *path == ':')
b86bc4cf 340#endif /* WIN32 */
fa73b229 341 {
342 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
343 *bufptr++ = '/';
344
345 strlcpy(bufptr, filename, bufend - bufptr);
346
4400e98d 347#ifdef WIN32
fa73b229 348 if (!access(buffer, 0))
4400e98d 349#else
350 if (!access(buffer, executable ? X_OK : 0))
351#endif /* WIN32 */
b86bc4cf 352 {
353 DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
fa73b229 354 return (buffer);
b86bc4cf 355 }
fa73b229 356
357 bufptr = buffer;
358 }
359 else if (bufptr < bufend)
360 *bufptr++ = *path;
361
362 path ++;
363 }
364
365 /*
366 * Check the last path...
367 */
368
369 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
370 *bufptr++ = '/';
371
372 strlcpy(bufptr, filename, bufend - bufptr);
373
374 if (!access(buffer, 0))
b86bc4cf 375 {
376 DEBUG_printf(("cupsFileFind: Returning \"%s\"\n", buffer));
fa73b229 377 return (buffer);
b86bc4cf 378 }
fa73b229 379 else
b86bc4cf 380 {
381 DEBUG_puts("cupsFileFind: Returning NULL");
fa73b229 382 return (NULL);
b86bc4cf 383 }
fa73b229 384}
385
386
ef416fc2 387/*
388 * 'cupsFileFlush()' - Flush pending output.
389 */
390
391int /* O - 0 on success, -1 on error */
392cupsFileFlush(cups_file_t *fp) /* I - CUPS file */
393{
2abf387c 394 ssize_t bytes; /* Bytes to write */
ef416fc2 395
396
397 DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
398
399 /*
400 * Range check input...
401 */
402
403 if (!fp || fp->mode != 'w')
404 {
405 DEBUG_puts(" Attempt to flush a read-only file...");
406 return (-1);
407 }
408
b86bc4cf 409 bytes = (ssize_t)(fp->ptr - fp->buf);
ef416fc2 410
ecdc0628 411 DEBUG_printf((" Flushing %ld bytes...\n", (long)bytes));
412
ef416fc2 413 if (bytes > 0)
414 {
415#ifdef HAVE_LIBZ
416 if (fp->compressed)
417 bytes = cups_compress(fp, fp->buf, bytes);
418 else
419#endif /* HAVE_LIBZ */
420 bytes = cups_write(fp, fp->buf, bytes);
421
422 if (bytes < 0)
423 return (-1);
424
425 fp->ptr = fp->buf;
426 }
427
428 return (0);
429}
430
431
432/*
433 * 'cupsFileGetChar()' - Get a single character from a file.
434 */
435
436int /* O - Character or -1 on EOF */
437cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
438{
439 /*
440 * Range check input...
441 */
442
443 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
b86bc4cf 444 {
445 DEBUG_puts("cupsFileGetChar: Bad arguments!");
ef416fc2 446 return (-1);
b86bc4cf 447 }
ef416fc2 448
449 /*
450 * If the input buffer is empty, try to read more data...
451 */
452
453 if (fp->ptr >= fp->end)
454 if (cups_fill(fp) < 0)
b86bc4cf 455 {
456 DEBUG_puts("cupsFileGetChar: Unable to fill buffer!");
ef416fc2 457 return (-1);
b86bc4cf 458 }
ef416fc2 459
460 /*
461 * Return the next character in the buffer...
462 */
463
b86bc4cf 464 DEBUG_printf(("cupsFileGetChar: Returning %d...\n", *(fp->ptr) & 255));
465
ef416fc2 466 return (*(fp->ptr)++ & 255);
467}
468
469
470/*
471 * 'cupsFileGetConf()' - Get a line from a configuration file...
472 */
473
ecdc0628 474char * /* O - Line read or NULL on eof/error */
ef416fc2 475cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
476 char *buf, /* O - String buffer */
477 size_t buflen, /* I - Size of string buffer */
478 char **value, /* O - Pointer to value */
479 int *linenum) /* IO - Current line number */
480{
481 char *ptr; /* Pointer into line */
482
483
484 /*
485 * Range check input...
486 */
487
488 if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
489 !buf || buflen < 2 || !value)
490 {
491 if (value)
492 *value = NULL;
493
494 return (NULL);
495 }
496
497 /*
498 * Read the next non-comment line...
499 */
500
501 *value = NULL;
f7deaa1a 502
ef416fc2 503 while (cupsFileGets(fp, buf, buflen))
504 {
505 (*linenum) ++;
506
507 /*
508 * Strip any comments...
509 */
510
511 if ((ptr = strchr(buf, '#')) != NULL)
512 {
f7deaa1a 513 if (ptr > buf && ptr[-1] == '\\')
ef416fc2 514 {
f7deaa1a 515 // Unquote the #...
516 _cups_strcpy(ptr - 1, ptr);
ef416fc2 517 }
f7deaa1a 518 else
519 {
520 // Strip the comment and any trailing whitespace...
521 while (ptr > buf)
522 {
523 if (!isspace(ptr[-1] & 255))
524 break;
525
526 ptr --;
527 }
ef416fc2 528
f7deaa1a 529 *ptr = '\0';
530 }
ef416fc2 531 }
532
533 /*
534 * Strip leading whitespace...
535 */
536
537 for (ptr = buf; isspace(*ptr & 255); ptr ++);
538
539 if (ptr > buf)
540 _cups_strcpy(buf, ptr);
541
542 /*
543 * See if there is anything left...
544 */
545
546 if (buf[0])
547 {
548 /*
549 * Yes, grab any value and return...
550 */
551
552 for (ptr = buf; *ptr; ptr ++)
553 if (isspace(*ptr & 255))
554 break;
555
556 if (*ptr)
557 {
558 /*
559 * Have a value, skip any other spaces...
560 */
561
562 while (isspace(*ptr & 255))
563 *ptr++ = '\0';
564
565 if (*ptr)
566 *value = ptr;
567
568 /*
569 * Strip trailing whitespace and > for lines that begin with <...
570 */
571
572 ptr += strlen(ptr) - 1;
573
574 if (buf[0] == '<' && *ptr == '>')
575 *ptr-- = '\0';
576 else if (buf[0] == '<' && *ptr != '>')
577 {
578 /*
579 * Syntax error...
580 */
581
582 *value = NULL;
583 return (buf);
584 }
585
586 while (ptr > *value && isspace(*ptr & 255))
587 *ptr-- = '\0';
588 }
589
590 /*
591 * Return the line...
592 */
593
594 return (buf);
595 }
596 }
597
598 return (NULL);
599}
600
601
80ca4592 602/*
603 * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
604 * contain binary data.
605 *
606 * This function differs from cupsFileGets() in that the trailing CR and LF
607 * are preserved, as is any binary data on the line. The buffer is nul-
608 * terminated, however you should use the returned length to determine
609 * the number of bytes on the line.
610 */
611
612size_t /* O - Number of bytes on line or 0 on EOF */
613cupsFileGetLine(cups_file_t *fp, /* I - File to read from */
614 char *buf, /* I - Buffer */
615 size_t buflen) /* I - Size of buffer */
616{
617 int ch; /* Character from file */
618 char *ptr, /* Current position in line buffer */
619 *end; /* End of line buffer */
620
621
622 /*
623 * Range check input...
624 */
625
626 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
627 return (0);
628
629 /*
630 * Now loop until we have a valid line...
631 */
632
633 for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
634 {
635 if (fp->ptr >= fp->end)
636 if (cups_fill(fp) <= 0)
637 break;
638
639 *ptr++ = ch = *(fp->ptr)++;
640
641 if (ch == '\r')
642 {
643 /*
644 * Check for CR LF...
645 */
646
647 if (fp->ptr >= fp->end)
648 if (cups_fill(fp) <= 0)
649 break;
650
651 if (*(fp->ptr) == '\n')
652 *ptr++ = *(fp->ptr)++;
653
654 break;
655 }
656 else if (ch == '\n')
657 {
658 /*
659 * Line feed ends a line...
660 */
661
662 break;
663 }
664 }
665
666 *ptr = '\0';
667
668 return (ptr - buf);
669}
670
671
ef416fc2 672/*
673 * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
674 */
675
676char * /* O - Line read or NULL on eof/error */
677cupsFileGets(cups_file_t *fp, /* I - CUPS file */
678 char *buf, /* O - String buffer */
679 size_t buflen) /* I - Size of string buffer */
680{
681 int ch; /* Character from file */
682 char *ptr, /* Current position in line buffer */
683 *end; /* End of line buffer */
684
685
686 /*
687 * Range check input...
688 */
689
690 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
691 return (NULL);
692
693 /*
694 * Now loop until we have a valid line...
695 */
696
697 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
698 {
699 if (fp->ptr >= fp->end)
700 if (cups_fill(fp) <= 0)
701 {
702 if (ptr == buf)
703 return (NULL);
704 else
705 break;
706 }
707
708 ch = *(fp->ptr)++;
709
710 if (ch == '\r')
711 {
712 /*
713 * Check for CR LF...
714 */
715
716 if (fp->ptr >= fp->end)
717 if (cups_fill(fp) <= 0)
718 break;
719
720 if (*(fp->ptr) == '\n')
721 fp->ptr ++;
722
723 break;
724 }
725 else if (ch == '\n')
726 {
727 /*
728 * Line feed ends a line...
729 */
730
731 break;
732 }
733 else
734 *ptr++ = ch;
735 }
736
737 *ptr = '\0';
738
739 return (buf);
740}
741
742
743/*
744 * 'cupsFileLock()' - Temporarily lock access to a file.
745 */
746
747int /* O - 0 on success, -1 on error */
748cupsFileLock(cups_file_t *fp, /* I - File to lock */
749 int block) /* I - 1 to wait for the lock, 0 to fail right away */
750{
751 /*
752 * Range check...
753 */
754
755 if (!fp || fp->mode == 's')
756 return (-1);
757
758 /*
759 * Try the lock...
760 */
761
762#ifdef WIN32
763 return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
764#else
765 return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
766#endif /* WIN32 */
767}
768
769
770/*
771 * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
772 */
773
774int /* O - File descriptor */
775cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
776{
777 return (fp->fd);
778}
779
780
781/*
782 * 'cupsFileOpen()' - Open a CUPS file.
783 */
784
785cups_file_t * /* O - CUPS file or NULL */
786cupsFileOpen(const char *filename, /* I - Name of file */
787 const char *mode) /* I - Open mode */
788{
789 cups_file_t *fp; /* New CUPS file */
790 int fd; /* File descriptor */
791 char hostname[1024], /* Hostname */
792 *portname; /* Port "name" (number or service) */
793 http_addrlist_t *addrlist; /* Host address list */
794
795
b423cd4c 796 DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")\n", filename,
797 mode));
798
ef416fc2 799 /*
800 * Range check input...
801 */
802
803 if (!filename || !mode ||
804 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
805 return (NULL);
806
807 /*
808 * Open the file...
809 */
810
811 switch (*mode)
812 {
813 case 'a' : /* Append file */
b86bc4cf 814 fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
ef416fc2 815 break;
816
817 case 'r' : /* Read file */
b86bc4cf 818 fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
ef416fc2 819 break;
820
821 case 'w' : /* Write file */
b86bc4cf 822 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
ef416fc2 823 break;
824
825 case 's' : /* Read/write socket */
826 strlcpy(hostname, filename, sizeof(hostname));
827 if ((portname = strrchr(hostname, ':')) != NULL)
828 *portname++ = '\0';
829 else
830 return (NULL);
831
832 /*
833 * Lookup the hostname and service...
834 */
835
836 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
837 return (NULL);
838
839 /*
840 * Connect to the server...
841 */
842
843 if (!httpAddrConnect(addrlist, &fd))
844 {
845 httpAddrFreeList(addrlist);
846 return (NULL);
847 }
848
849 httpAddrFreeList(addrlist);
850 break;
851
852 default : /* Remove bogus compiler warning... */
853 return (NULL);
854 }
855
856 if (fd < 0)
857 return (NULL);
858
859 /*
860 * Create the CUPS file structure...
861 */
862
863 if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
864 {
865 if (*mode == 's')
866 closesocket(fd);
867 else
868 close(fd);
869 }
870
871 /*
872 * Return it...
873 */
874
875 return (fp);
876}
877
878/*
879 * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
880 */
881
882cups_file_t * /* O - CUPS file or NULL */
883cupsFileOpenFd(int fd, /* I - File descriptor */
884 const char *mode) /* I - Open mode */
885{
886 cups_file_t *fp; /* New CUPS file */
887
888
b423cd4c 889 DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")\n", fd, mode));
890
ef416fc2 891 /*
892 * Range check input...
893 */
894
895 if (fd < 0 || !mode ||
896 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
897 return (NULL);
898
899 /*
900 * Allocate memory...
901 */
902
903 if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
904 return (NULL);
905
906 /*
907 * Open the file...
908 */
909
910 fp->fd = fd;
911
912 switch (*mode)
913 {
914 case 'w' :
915 case 'a' :
916 fp->mode = 'w';
917 fp->ptr = fp->buf;
918 fp->end = fp->buf + sizeof(fp->buf);
919
920#ifdef HAVE_LIBZ
921 if (mode[1] >= '1' && mode[1] <= '9')
922 {
923 /*
924 * Open a compressed stream, so write the standard gzip file
925 * header...
926 */
927
928 unsigned char header[10]; /* gzip file header */
929 time_t curtime; /* Current time */
930
931
932 curtime = time(NULL);
933 header[0] = 0x1f;
934 header[1] = 0x8b;
935 header[2] = Z_DEFLATED;
936 header[3] = 0;
937 header[4] = curtime;
938 header[5] = curtime >> 8;
939 header[6] = curtime >> 16;
940 header[7] = curtime >> 24;
941 header[8] = 0;
942 header[9] = 0x03;
943
944 cups_write(fp, (char *)header, 10);
945
946 /*
947 * Initialize the compressor...
948 */
949
950 deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
951 Z_DEFAULT_STRATEGY);
952
953 fp->stream.next_out = fp->cbuf;
954 fp->stream.avail_out = sizeof(fp->cbuf);
955 fp->compressed = 1;
956 fp->crc = crc32(0L, Z_NULL, 0);
957 }
958#endif /* HAVE_LIBZ */
959 break;
960
961 case 'r' :
962 fp->mode = 'r';
963 break;
964
965 case 's' :
966 fp->mode = 's';
967 break;
968
969 default : /* Remove bogus compiler warning... */
970 return (NULL);
971 }
972
973 /*
974 * Don't pass this file to child processes...
975 */
976
977#ifndef WIN32
978 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
979#endif /* !WIN32 */
980
981 return (fp);
982}
983
984
985/*
986 * 'cupsFilePeekChar()' - Peek at the next character from a file.
987 */
988
989int /* O - Character or -1 on EOF */
990cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
991{
992 /*
993 * Range check input...
994 */
995
996 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
997 return (-1);
998
999 /*
1000 * If the input buffer is empty, try to read more data...
1001 */
1002
1003 if (fp->ptr >= fp->end)
1004 if (cups_fill(fp) < 0)
1005 return (-1);
1006
1007 /*
1008 * Return the next character in the buffer...
1009 */
1010
1011 return (*(fp->ptr) & 255);
1012}
1013
1014
1015/*
1016 * 'cupsFilePrintf()' - Write a formatted string.
1017 */
1018
1019int /* O - Number of bytes written or -1 */
1020cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
1021 const char *format, /* I - Printf-style format string */
1022 ...) /* I - Additional args as necessary */
1023{
1024 va_list ap; /* Argument list */
2abf387c 1025 ssize_t bytes; /* Formatted size */
ecdc0628 1026 char buf[8192]; /* Formatted text */
1027
ef416fc2 1028
ecdc0628 1029 DEBUG_printf(("cupsFilePrintf(fp=%p, format=\"%s\", ...)\n", fp, format));
ef416fc2 1030
1031 if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1032 return (-1);
1033
1034 va_start(ap, format);
1035 bytes = vsnprintf(buf, sizeof(buf), format, ap);
1036 va_end(ap);
1037
ecdc0628 1038 if (bytes >= sizeof(buf))
1039 return (-1);
1040
ef416fc2 1041 if (fp->mode == 's')
1042 return (cups_write(fp, buf, bytes));
1043
1044 if ((fp->ptr + bytes) > fp->end)
1045 if (cupsFileFlush(fp))
1046 return (-1);
1047
1048 fp->pos += bytes;
1049
1050 if (bytes > sizeof(fp->buf))
1051 {
1052#ifdef HAVE_LIBZ
1053 if (fp->compressed)
1054 return (cups_compress(fp, buf, bytes));
1055 else
1056#endif /* HAVE_LIBZ */
1057 return (cups_write(fp, buf, bytes));
1058 }
1059 else
1060 {
1061 memcpy(fp->ptr, buf, bytes);
1062 fp->ptr += bytes;
1063 return (bytes);
1064 }
1065}
1066
1067
1068/*
1069 * 'cupsFilePutChar()' - Write a character.
1070 */
1071
1072int /* O - 0 on success, -1 on error */
1073cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
1074 int c) /* I - Character to write */
1075{
1076 /*
1077 * Range check input...
1078 */
1079
1080 if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1081 return (-1);
1082
1083 if (fp->mode == 's')
1084 {
1085 /*
1086 * Send character immediately over socket...
1087 */
1088
1089 char ch; /* Output character */
1090
1091
1092 ch = c;
1093
1094 if (send(fp->fd, &ch, 1, 0) < 1)
1095 return (-1);
1096 }
1097 else
1098 {
1099 /*
1100 * Buffer it up...
1101 */
1102
1103 if (fp->ptr >= fp->end)
1104 if (cupsFileFlush(fp))
1105 return (-1);
1106
1107 *(fp->ptr) ++ = c;
1108 }
1109
1110 fp->pos ++;
1111
1112 return (0);
1113}
1114
1115
1116/*
1117 * 'cupsFilePuts()' - Write a string.
1118 */
1119
1120int /* O - Number of bytes written or -1 */
1121cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
1122 const char *s) /* I - String to write */
1123{
2abf387c 1124 ssize_t bytes; /* Bytes to write */
ef416fc2 1125
1126
1127 /*
1128 * Range check input...
1129 */
1130
1131 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1132 return (-1);
1133
1134 /*
1135 * Write the string...
1136 */
1137
b86bc4cf 1138 bytes = (int)strlen(s);
ef416fc2 1139
1140 if (fp->mode == 's')
1141 {
1142 if (cups_write(fp, s, bytes) < 0)
1143 return (-1);
1144
1145 fp->pos += bytes;
1146
1147 return (bytes);
1148 }
1149
1150 if ((fp->ptr + bytes) > fp->end)
1151 if (cupsFileFlush(fp))
1152 return (-1);
1153
1154 fp->pos += bytes;
1155
1156 if (bytes > sizeof(fp->buf))
1157 {
1158#ifdef HAVE_LIBZ
1159 if (fp->compressed)
1160 return (cups_compress(fp, s, bytes));
1161 else
1162#endif /* HAVE_LIBZ */
1163 return (cups_write(fp, s, bytes));
1164 }
1165 else
1166 {
1167 memcpy(fp->ptr, s, bytes);
1168 fp->ptr += bytes;
1169 return (bytes);
1170 }
1171}
1172
1173
1174/*
1175 * 'cupsFileRead()' - Read from a file.
1176 */
1177
1178ssize_t /* O - Number of bytes read or -1 */
1179cupsFileRead(cups_file_t *fp, /* I - CUPS file */
1180 char *buf, /* O - Buffer */
1181 size_t bytes) /* I - Number of bytes to read */
1182{
2abf387c 1183 size_t total; /* Total bytes read */
1184 ssize_t count; /* Bytes read */
ef416fc2 1185
1186
1187 DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1188 (long)bytes));
1189
1190 /*
1191 * Range check input...
1192 */
1193
1194 if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
1195 return (-1);
1196
1197 if (bytes == 0)
1198 return (0);
1199
1200 /*
1201 * Loop until all bytes are read...
1202 */
1203
1204 total = 0;
1205 while (bytes > 0)
1206 {
1207 if (fp->ptr >= fp->end)
1208 if (cups_fill(fp) <= 0)
1209 {
1210 DEBUG_printf((" cups_fill() returned -1, total=%d\n", total));
1211
1212 if (total > 0)
b86bc4cf 1213 return ((ssize_t)total);
ef416fc2 1214 else
1215 return (-1);
1216 }
1217
b86bc4cf 1218 count = (ssize_t)(fp->end - fp->ptr);
1219 if (count > (ssize_t)bytes)
1220 count = (ssize_t)bytes;
ef416fc2 1221
1222 memcpy(buf, fp->ptr, count);
1223 fp->ptr += count;
1224
1225 /*
1226 * Update the counts for the last read...
1227 */
1228
1229 bytes -= count;
1230 total += count;
1231 buf += count;
1232 }
1233
1234 /*
1235 * Return the total number of bytes read...
1236 */
1237
1238 DEBUG_printf((" total=%d\n", total));
1239
b86bc4cf 1240 return ((ssize_t)total);
ef416fc2 1241}
1242
1243
1244/*
1245 * 'cupsFileRewind()' - Rewind a file.
1246 */
1247
1248off_t /* O - New file position or -1 */
1249cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
1250{
80ca4592 1251 /*
1252 * Range check input...
1253 */
1254
1255 if (!fp || fp->mode != 'r')
1256 return (-1);
1257
1258 /*
1259 * Handle special cases...
1260 */
1261
1262 if (fp->pos == 0)
1263 {
1264 /*
1265 * No seeking necessary...
1266 */
1267
1268 if (fp->ptr)
1269 {
1270 fp->ptr = fp->buf;
1271 fp->eof = 0;
1272 }
1273
1274 return (0);
1275 }
1276
1277 /*
1278 * Otherwise, seek in the file and cleanup any compression buffers...
1279 */
1280
1281#ifdef HAVE_LIBZ
1282 if (fp->compressed)
1283 {
1284 inflateEnd(&fp->stream);
1285 fp->compressed = 0;
1286 }
1287#endif /* HAVE_LIBZ */
1288
1289 lseek(fp->fd, 0, SEEK_SET);
1290
1291 fp->pos = 0;
1292 fp->ptr = NULL;
1293 fp->end = NULL;
d09495fa 1294 fp->eof = 0;
80ca4592 1295
1296 return (0);
ef416fc2 1297}
1298
1299
1300/*
1301 * 'cupsFileSeek()' - Seek in a file.
1302 */
1303
1304off_t /* O - New file position or -1 */
1305cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
1306 off_t pos) /* I - Position in file */
1307{
2abf387c 1308 ssize_t bytes; /* Number bytes in buffer */
ef416fc2 1309
1310
b423cd4c 1311 DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp, pos));
1312 DEBUG_printf((" fp->pos=" CUPS_LLFMT "\n", fp->pos));
1313 DEBUG_printf((" fp->ptr=%p, fp->end=%p\n", fp->ptr, fp->end));
ef416fc2 1314
1315 /*
1316 * Range check input...
1317 */
1318
1319 if (!fp || pos < 0 || fp->mode != 'r')
1320 return (-1);
1321
80ca4592 1322 /*
1323 * Handle special cases...
1324 */
1325
1326 if (pos == 0)
1327 return (cupsFileRewind(fp));
1328
b423cd4c 1329 if (fp->pos == pos)
1330 {
1331 /*
1332 * No seeking necessary...
1333 */
1334
1335 if (fp->ptr)
1336 {
1337 fp->ptr = fp->buf;
1338 fp->eof = 0;
1339 }
1340
1341 return (pos);
1342 }
1343
80ca4592 1344#ifdef HAVE_LIBZ
1345 if (!fp->compressed && !fp->ptr)
1346 {
1347 /*
1348 * Preload a buffer to determine whether the file is compressed...
1349 */
1350
1351 if (cups_fill(fp) < 0)
1352 return (-1);
1353 }
1354#endif /* HAVE_LIBZ */
1355
ef416fc2 1356 /*
1357 * Figure out the number of bytes in the current buffer, and then
1358 * see if we are outside of it...
1359 */
1360
80ca4592 1361 if (fp->ptr)
b86bc4cf 1362 bytes = (ssize_t)(fp->end - fp->buf);
80ca4592 1363 else
1364 bytes = 0;
1365
ef416fc2 1366 fp->eof = 0;
1367
80ca4592 1368 DEBUG_printf((" bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
1369
ef416fc2 1370 if (pos < fp->pos)
1371 {
1372 /*
1373 * Need to seek backwards...
1374 */
1375
80ca4592 1376 DEBUG_puts(" SEEK BACKWARDS");
1377
ef416fc2 1378#ifdef HAVE_LIBZ
1379 if (fp->compressed)
1380 {
1381 inflateEnd(&fp->stream);
1382
1383 lseek(fp->fd, 0, SEEK_SET);
1384 fp->pos = 0;
1385 fp->ptr = NULL;
1386 fp->end = NULL;
1387
1388 while ((bytes = cups_fill(fp)) > 0)
1389 if (pos >= fp->pos && pos < (fp->pos + bytes))
1390 break;
1391
1392 if (bytes <= 0)
1393 return (-1);
80ca4592 1394
1395 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1396 }
1397 else
1398#endif /* HAVE_LIBZ */
1399 {
1400 fp->pos = lseek(fp->fd, pos, SEEK_SET);
ef416fc2 1401 fp->ptr = NULL;
1402 fp->end = NULL;
80ca4592 1403
1404 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
ef416fc2 1405 }
1406 }
1407 else if (pos >= (fp->pos + bytes))
1408 {
1409 /*
1410 * Need to seek forwards...
1411 */
1412
80ca4592 1413 DEBUG_puts(" SEEK FORWARDS");
1414
ef416fc2 1415#ifdef HAVE_LIBZ
80ca4592 1416 if (fp->compressed)
ef416fc2 1417 {
1418 while ((bytes = cups_fill(fp)) > 0)
80ca4592 1419 {
ef416fc2 1420 if (pos >= fp->pos && pos < (fp->pos + bytes))
1421 break;
80ca4592 1422 }
ef416fc2 1423
1424 if (bytes <= 0)
1425 return (-1);
80ca4592 1426
1427 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1428 }
1429 else
1430#endif /* HAVE_LIBZ */
1431 {
1432 fp->pos = lseek(fp->fd, pos, SEEK_SET);
ef416fc2 1433 fp->ptr = NULL;
1434 fp->end = NULL;
80ca4592 1435
1436 DEBUG_printf((" lseek() returned " CUPS_LLFMT "...\n", fp->pos));
ef416fc2 1437 }
1438 }
1439 else
1440 {
1441 /*
1442 * Just reposition the current pointer, since we have the right
1443 * range...
1444 */
1445
80ca4592 1446 DEBUG_puts(" SEEK INSIDE BUFFER");
1447
ef416fc2 1448 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1449 }
1450
1451 return (fp->pos);
1452}
1453
1454
80ca4592 1455/*
1456 * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1457 */
1458
1459cups_file_t *
1460cupsFileStderr(void)
1461{
1462 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1463
1464
1465 /*
1466 * Open file descriptor 2 as needed...
1467 */
1468
1469 if (!cg->stdio_files[2])
1470 {
1471 /*
1472 * Flush any pending output on the stdio file...
1473 */
1474
1475 fflush(stderr);
1476
1477 /*
1478 * Open file descriptor 2...
1479 */
1480
1481 if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1482 cg->stdio_files[2]->is_stdio = 1;
1483 }
1484
1485 return (cg->stdio_files[2]);
1486}
1487
1488
1489/*
1490 * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1491 */
1492
1493cups_file_t *
1494cupsFileStdin(void)
1495{
1496 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1497
1498
1499 /*
1500 * Open file descriptor 0 as needed...
1501 */
1502
1503 if (!cg->stdio_files[0])
1504 {
1505 /*
1506 * Open file descriptor 0...
1507 */
1508
1509 if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1510 cg->stdio_files[0]->is_stdio = 1;
1511 }
1512
1513 return (cg->stdio_files[0]);
1514}
1515
1516
1517/*
1518 * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1519 */
1520
1521cups_file_t *
1522cupsFileStdout(void)
1523{
1524 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1525
1526
1527 /*
1528 * Open file descriptor 1 as needed...
1529 */
1530
1531 if (!cg->stdio_files[1])
1532 {
1533 /*
1534 * Flush any pending output on the stdio file...
1535 */
1536
1537 fflush(stdout);
1538
1539 /*
1540 * Open file descriptor 1...
1541 */
1542
1543 if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1544 cg->stdio_files[1]->is_stdio = 1;
1545 }
1546
1547 return (cg->stdio_files[1]);
1548}
1549
1550
ef416fc2 1551/*
1552 * 'cupsFileTell()' - Return the current file position.
1553 */
1554
1555off_t /* O - File position */
1556cupsFileTell(cups_file_t *fp) /* I - CUPS file */
1557{
80ca4592 1558 return (fp ? fp->pos : 0);
ef416fc2 1559}
1560
1561
1562/*
1563 * 'cupsFileUnlock()' - Unlock access to a file.
1564 */
1565
1566int /* O - 0 on success, -1 on error */
1567cupsFileUnlock(cups_file_t *fp) /* I - File to lock */
1568{
1569 /*
1570 * Range check...
1571 */
1572
1573 if (!fp || fp->mode == 's')
1574 return (-1);
1575
1576 /*
1577 * Unlock...
1578 */
1579
1580#ifdef WIN32
1581 return (locking(fp->fd, _LK_UNLCK, 0));
1582#else
1583 return (lockf(fp->fd, F_ULOCK, 0));
1584#endif /* WIN32 */
1585}
1586
1587
1588/*
1589 * 'cupsFileWrite()' - Write to a file.
1590 */
1591
1592ssize_t /* O - Number of bytes written */
1593cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
1594 const char *buf, /* I - Buffer */
1595 size_t bytes) /* I - Number of bytes to write */
1596{
1597 /*
1598 * Range check input...
1599 */
1600
1601 if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
1602 return (-1);
1603
1604 if (bytes == 0)
1605 return (0);
1606
1607 /*
1608 * Write the buffer...
1609 */
1610
1611 if (fp->mode == 's')
1612 {
1613 if (cups_write(fp, buf, bytes) < 0)
1614 return (-1);
1615
b86bc4cf 1616 fp->pos += (off_t)bytes;
ef416fc2 1617
b86bc4cf 1618 return ((ssize_t)bytes);
ef416fc2 1619 }
1620
1621 if ((fp->ptr + bytes) > fp->end)
1622 if (cupsFileFlush(fp))
1623 return (-1);
1624
b86bc4cf 1625 fp->pos += (off_t)bytes;
ef416fc2 1626
1627 if (bytes > sizeof(fp->buf))
1628 {
1629#ifdef HAVE_LIBZ
1630 if (fp->compressed)
1631 return (cups_compress(fp, buf, bytes));
1632 else
1633#endif /* HAVE_LIBZ */
1634 return (cups_write(fp, buf, bytes));
1635 }
1636 else
1637 {
1638 memcpy(fp->ptr, buf, bytes);
1639 fp->ptr += bytes;
b86bc4cf 1640 return ((ssize_t)bytes);
ef416fc2 1641 }
1642}
1643
1644
1645#ifdef HAVE_LIBZ
1646/*
1647 * 'cups_compress()' - Compress a buffer of data...
1648 */
1649
1650static ssize_t /* O - Number of bytes written or -1 */
1651cups_compress(cups_file_t *fp, /* I - CUPS file */
1652 const char *buf, /* I - Buffer */
1653 size_t bytes) /* I - Number bytes */
1654{
ecdc0628 1655 DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1656 (long)bytes));
1657
ef416fc2 1658 /*
1659 * Update the CRC...
1660 */
1661
1662 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
1663
1664 /*
1665 * Deflate the bytes...
1666 */
1667
1668 fp->stream.next_in = (Bytef *)buf;
1669 fp->stream.avail_in = bytes;
1670
1671 while (fp->stream.avail_in > 0)
1672 {
1673 /*
1674 * Flush the current buffer...
1675 */
1676
ecdc0628 1677 DEBUG_printf((" avail_in=%d, avail_out=%d\n", fp->stream.avail_in,
1678 fp->stream.avail_out));
1679
ef416fc2 1680 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
1681 {
1682 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
1683 return (-1);
ecdc0628 1684
1685 fp->stream.next_out = fp->cbuf;
1686 fp->stream.avail_out = sizeof(fp->cbuf);
ef416fc2 1687 }
1688
1689 deflate(&(fp->stream), Z_NO_FLUSH);
1690 }
1691
1692 return (bytes);
1693}
1694#endif /* HAVE_LIBZ */
1695
1696
1697/*
1698 * 'cups_fill()' - Fill the input buffer...
1699 */
1700
1701static ssize_t /* O - Number of bytes or -1 */
1702cups_fill(cups_file_t *fp) /* I - CUPS file */
1703{
1704 ssize_t bytes; /* Number of bytes read */
1705#ifdef HAVE_LIBZ
1706 const unsigned char *ptr, /* Pointer into buffer */
1707 *end; /* End of buffer */
1708#endif /* HAVE_LIBZ */
1709
1710
1711 DEBUG_printf(("cups_fill(fp=%p)\n", fp));
b423cd4c 1712 DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, "
1713 "fp->pos=" CUPS_LLFMT ", fp->eof=%d\n",
1714 fp->ptr, fp->end, fp->buf, fp->pos, fp->eof));
ef416fc2 1715
1716 /*
1717 * Update the "pos" element as needed...
1718 */
1719
1720 if (fp->ptr && fp->end)
b86bc4cf 1721 fp->pos += (off_t)(fp->end - fp->buf);
ef416fc2 1722
1723#ifdef HAVE_LIBZ
b423cd4c 1724 DEBUG_printf((" fp->compressed=%d\n", fp->compressed));
1725
ef416fc2 1726 while (!fp->ptr || fp->compressed)
1727 {
1728 /*
1729 * Check to see if we have read any data yet; if not, see if we have a
1730 * compressed file...
1731 */
1732
1733 if (!fp->ptr)
1734 {
1735 /*
1736 * Reset the file position in case we are seeking...
1737 */
1738
1739 fp->compressed = 0;
ef416fc2 1740
1741 /*
1742 * Read the first bytes in the file to determine if we have a gzip'd
1743 * file...
1744 */
1745
fa73b229 1746 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
ef416fc2 1747 {
1748 /*
1749 * Can't read from file!
1750 */
1751
b423cd4c 1752 DEBUG_printf((" cups_read() returned " CUPS_LLFMT "!\n",
1753 CUPS_LLCAST bytes));
1754
ef416fc2 1755 return (-1);
1756 }
1757
fa73b229 1758 if (bytes < 10 || fp->buf[0] != 0x1f ||
e00b005a 1759 (fp->buf[1] & 255) != 0x8b ||
fa73b229 1760 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
ef416fc2 1761 {
1762 /*
1763 * Not a gzip'd file!
1764 */
1765
ef416fc2 1766 fp->ptr = fp->buf;
1767 fp->end = fp->buf + bytes;
1768
b423cd4c 1769 DEBUG_printf((" returning " CUPS_LLFMT "!\n", CUPS_LLCAST bytes));
1770
ef416fc2 1771 return (bytes);
1772 }
1773
1774 /*
1775 * Parse header junk: extra data, original name, and comment...
1776 */
1777
fa73b229 1778 ptr = (unsigned char *)fp->buf + 10;
1779 end = (unsigned char *)fp->buf + bytes;
ef416fc2 1780
fa73b229 1781 if (fp->buf[3] & 0x04)
ef416fc2 1782 {
1783 /*
1784 * Skip extra data...
1785 */
1786
1787 if ((ptr + 2) > end)
1788 {
1789 /*
1790 * Can't read from file!
1791 */
1792
1793 return (-1);
1794 }
1795
1796 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1797 ptr += 2 + bytes;
1798
1799 if (ptr > end)
1800 {
1801 /*
1802 * Can't read from file!
1803 */
1804
1805 return (-1);
1806 }
1807 }
1808
fa73b229 1809 if (fp->buf[3] & 0x08)
ef416fc2 1810 {
1811 /*
1812 * Skip original name data...
1813 */
1814
1815 while (ptr < end && *ptr)
1816 ptr ++;
1817
1818 if (ptr < end)
1819 ptr ++;
1820 else
1821 {
1822 /*
1823 * Can't read from file!
1824 */
1825
1826 return (-1);
1827 }
1828 }
1829
fa73b229 1830 if (fp->buf[3] & 0x10)
ef416fc2 1831 {
1832 /*
1833 * Skip comment data...
1834 */
1835
1836 while (ptr < end && *ptr)
1837 ptr ++;
1838
1839 if (ptr < end)
1840 ptr ++;
1841 else
1842 {
1843 /*
1844 * Can't read from file!
1845 */
1846
1847 return (-1);
1848 }
1849 }
1850
fa73b229 1851 if (fp->buf[3] & 0x02)
ef416fc2 1852 {
1853 /*
1854 * Skip header CRC data...
1855 */
1856
1857 ptr += 2;
1858
1859 if (ptr > end)
1860 {
1861 /*
1862 * Can't read from file!
1863 */
1864
1865 return (-1);
1866 }
1867 }
1868
fa73b229 1869 /*
1870 * Copy the flate-compressed data to the compression buffer...
1871 */
1872
1873 if ((bytes = end - ptr) > 0)
1874 memcpy(fp->cbuf, ptr, bytes);
1875
ef416fc2 1876 /*
1877 * Setup the decompressor data...
1878 */
1879
1880 fp->stream.zalloc = (alloc_func)0;
1881 fp->stream.zfree = (free_func)0;
1882 fp->stream.opaque = (voidpf)0;
fa73b229 1883 fp->stream.next_in = (Bytef *)fp->cbuf;
ef416fc2 1884 fp->stream.next_out = NULL;
fa73b229 1885 fp->stream.avail_in = bytes;
ef416fc2 1886 fp->stream.avail_out = 0;
1887 fp->crc = crc32(0L, Z_NULL, 0);
1888
1889 if (inflateInit2(&(fp->stream), -15) != Z_OK)
1890 return (-1);
1891
1892 fp->compressed = 1;
1893 }
1894
1895 if (fp->compressed)
1896 {
1897 /*
1898 * If we have reached end-of-file, return immediately...
1899 */
1900
1901 if (fp->eof)
1902 return (-1);
1903
1904 /*
1905 * Fill the decompression buffer as needed...
1906 */
1907
1908 if (fp->stream.avail_in == 0)
1909 {
1910 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1911 return (-1);
1912
1913 fp->stream.next_in = fp->cbuf;
1914 fp->stream.avail_in = bytes;
1915 }
1916
1917 /*
1918 * Decompress data from the buffer...
1919 */
1920
1921 fp->stream.next_out = (Bytef *)fp->buf;
1922 fp->stream.avail_out = sizeof(fp->buf);
1923
1924 if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
1925 {
1926 /*
1927 * Read the CRC and length...
1928 */
1929
1930 unsigned char trailer[8]; /* Trailer bytes */
1931 uLong tcrc; /* Trailer CRC */
1932
1933
1934 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
1935 {
1936 /*
1937 * Can't get it, so mark end-of-file...
1938 */
1939
1940 fp->eof = 1;
ef416fc2 1941 }
fa73b229 1942 else
1943 {
1944 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
1945 trailer[0];
ef416fc2 1946
fa73b229 1947 if (tcrc != fp->crc)
1948 {
1949 /*
1950 * Bad CRC, mark end-of-file...
1951 */
1952
1953 fp->eof = 1;
1954
1955 return (-1);
1956 }
ef416fc2 1957
ef416fc2 1958 /*
fa73b229 1959 * Otherwise, reset the compressed flag so that we re-read the
1960 * file header...
ef416fc2 1961 */
ef416fc2 1962
fa73b229 1963 fp->compressed = 0;
ef416fc2 1964 }
ef416fc2 1965 }
1966
1967 bytes = sizeof(fp->buf) - fp->stream.avail_out;
1968
1969 /*
1970 * Return the decompressed data...
1971 */
1972
1973 fp->ptr = fp->buf;
1974 fp->end = fp->buf + bytes;
1975
fa73b229 1976 if (bytes)
1977 return (bytes);
ef416fc2 1978 }
1979 }
1980#endif /* HAVE_LIBZ */
1981
1982 /*
1983 * Read a buffer's full of data...
1984 */
1985
1986 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1987 {
1988 /*
1989 * Can't read from file!
1990 */
1991
1992 fp->eof = 1;
1993 fp->ptr = fp->buf;
1994 fp->end = fp->buf;
1995
1996 return (-1);
1997 }
1998
1999 /*
2000 * Return the bytes we read...
2001 */
2002
2003 fp->eof = 0;
2004 fp->ptr = fp->buf;
2005 fp->end = fp->buf + bytes;
2006
2007 return (bytes);
2008}
2009
2010
2011/*
2012 * 'cups_read()' - Read from a file descriptor.
2013 */
2014
2015static ssize_t /* O - Number of bytes read or -1 */
2016cups_read(cups_file_t *fp, /* I - CUPS file */
2017 char *buf, /* I - Buffer */
2018 size_t bytes) /* I - Number bytes */
2019{
2020 ssize_t total; /* Total bytes read */
2021
2022
2023 /*
2024 * Loop until we read at least 0 bytes...
2025 */
2026
2027 for (;;)
2028 {
b86bc4cf 2029#ifdef WIN32
2030 if (fp->mode == 's')
2031 total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2032 else
2033 total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2034#else
ef416fc2 2035 if (fp->mode == 's')
2036 total = recv(fp->fd, buf, bytes, 0);
2037 else
2038 total = read(fp->fd, buf, bytes);
b86bc4cf 2039#endif /* WIN32 */
ef416fc2 2040
2041 if (total >= 0)
2042 break;
2043
2044 /*
2045 * Reads can be interrupted by signals and unavailable resources...
2046 */
2047
2048 if (errno == EAGAIN || errno == EINTR)
2049 continue;
2050 else
2051 return (-1);
2052 }
2053
2054 /*
2055 * Return the total number of bytes read...
2056 */
2057
2058 return (total);
2059}
2060
2061
2062/*
2063 * 'cups_write()' - Write to a file descriptor.
2064 */
2065
2066static ssize_t /* O - Number of bytes written or -1 */
2067cups_write(cups_file_t *fp, /* I - CUPS file */
2068 const char *buf, /* I - Buffer */
2069 size_t bytes) /* I - Number bytes */
2070{
2abf387c 2071 size_t total; /* Total bytes written */
2072 ssize_t count; /* Count this time */
ef416fc2 2073
2074
ecdc0628 2075 DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
2076 (long)bytes));
2077
ef416fc2 2078 /*
2079 * Loop until all bytes are written...
2080 */
2081
2082 total = 0;
2083 while (bytes > 0)
2084 {
b86bc4cf 2085#ifdef WIN32
2086 if (fp->mode == 's')
2087 count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2088 else
2089 count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2090#else
ef416fc2 2091 if (fp->mode == 's')
2092 count = send(fp->fd, buf, bytes, 0);
2093 else
2094 count = write(fp->fd, buf, bytes);
b86bc4cf 2095#endif /* WIN32 */
ef416fc2 2096
2097 if (count < 0)
2098 {
2099 /*
2100 * Writes can be interrupted by signals and unavailable resources...
2101 */
2102
2103 if (errno == EAGAIN || errno == EINTR)
2104 continue;
2105 else
2106 return (-1);
2107 }
2108
ecdc0628 2109 DEBUG_printf((" count=%ld\n", (long)count));
2110
ef416fc2 2111 /*
2112 * Update the counts for the last write call...
2113 */
2114
2115 bytes -= count;
2116 total += count;
2117 buf += count;
2118 }
2119
2120 /*
2121 * Return the total number of bytes written...
2122 */
2123
b86bc4cf 2124 return ((ssize_t)total);
ef416fc2 2125}
2126
2127
2128/*
bc44d920 2129 * End of "$Id: file.c 6649 2007-07-11 21:46:42Z mike $".
ef416fc2 2130 */