]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/file.c
Import CUPS 1.4svn r7023 into easysw/current.
[thirdparty/cups.git] / cups / file.c
CommitLineData
ef416fc2 1/*
2e4ff8af 2 * "$Id: file.c 6962 2007-09-17 20:35:47Z 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 {
c277e2f8 1210 DEBUG_printf((" cups_fill() returned -1, total=%d\n", (int)total));
ef416fc2 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
c277e2f8 1238 DEBUG_printf((" total=%d\n", (int)total));
ef416fc2 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
c277e2f8 1706 int status; /* Decompression status */
ef416fc2 1707 const unsigned char *ptr, /* Pointer into buffer */
1708 *end; /* End of buffer */
1709#endif /* HAVE_LIBZ */
1710
1711
1712 DEBUG_printf(("cups_fill(fp=%p)\n", fp));
b423cd4c 1713 DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, "
1714 "fp->pos=" CUPS_LLFMT ", fp->eof=%d\n",
1715 fp->ptr, fp->end, fp->buf, fp->pos, fp->eof));
ef416fc2 1716
1717 /*
1718 * Update the "pos" element as needed...
1719 */
1720
1721 if (fp->ptr && fp->end)
b86bc4cf 1722 fp->pos += (off_t)(fp->end - fp->buf);
ef416fc2 1723
1724#ifdef HAVE_LIBZ
b423cd4c 1725 DEBUG_printf((" fp->compressed=%d\n", fp->compressed));
1726
ef416fc2 1727 while (!fp->ptr || fp->compressed)
1728 {
1729 /*
1730 * Check to see if we have read any data yet; if not, see if we have a
1731 * compressed file...
1732 */
1733
1734 if (!fp->ptr)
1735 {
1736 /*
1737 * Reset the file position in case we are seeking...
1738 */
1739
1740 fp->compressed = 0;
ef416fc2 1741
1742 /*
1743 * Read the first bytes in the file to determine if we have a gzip'd
1744 * file...
1745 */
1746
fa73b229 1747 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
ef416fc2 1748 {
1749 /*
1750 * Can't read from file!
1751 */
1752
b423cd4c 1753 DEBUG_printf((" cups_read() returned " CUPS_LLFMT "!\n",
1754 CUPS_LLCAST bytes));
1755
ef416fc2 1756 return (-1);
1757 }
1758
fa73b229 1759 if (bytes < 10 || fp->buf[0] != 0x1f ||
e00b005a 1760 (fp->buf[1] & 255) != 0x8b ||
fa73b229 1761 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
ef416fc2 1762 {
1763 /*
1764 * Not a gzip'd file!
1765 */
1766
ef416fc2 1767 fp->ptr = fp->buf;
1768 fp->end = fp->buf + bytes;
1769
b423cd4c 1770 DEBUG_printf((" returning " CUPS_LLFMT "!\n", CUPS_LLCAST bytes));
1771
ef416fc2 1772 return (bytes);
1773 }
1774
1775 /*
1776 * Parse header junk: extra data, original name, and comment...
1777 */
1778
fa73b229 1779 ptr = (unsigned char *)fp->buf + 10;
1780 end = (unsigned char *)fp->buf + bytes;
ef416fc2 1781
fa73b229 1782 if (fp->buf[3] & 0x04)
ef416fc2 1783 {
1784 /*
1785 * Skip extra data...
1786 */
1787
1788 if ((ptr + 2) > end)
1789 {
1790 /*
1791 * Can't read from file!
1792 */
1793
1794 return (-1);
1795 }
1796
1797 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1798 ptr += 2 + bytes;
1799
1800 if (ptr > end)
1801 {
1802 /*
1803 * Can't read from file!
1804 */
1805
1806 return (-1);
1807 }
1808 }
1809
fa73b229 1810 if (fp->buf[3] & 0x08)
ef416fc2 1811 {
1812 /*
1813 * Skip original name data...
1814 */
1815
1816 while (ptr < end && *ptr)
1817 ptr ++;
1818
1819 if (ptr < end)
1820 ptr ++;
1821 else
1822 {
1823 /*
1824 * Can't read from file!
1825 */
1826
1827 return (-1);
1828 }
1829 }
1830
fa73b229 1831 if (fp->buf[3] & 0x10)
ef416fc2 1832 {
1833 /*
1834 * Skip comment data...
1835 */
1836
1837 while (ptr < end && *ptr)
1838 ptr ++;
1839
1840 if (ptr < end)
1841 ptr ++;
1842 else
1843 {
1844 /*
1845 * Can't read from file!
1846 */
1847
1848 return (-1);
1849 }
1850 }
1851
fa73b229 1852 if (fp->buf[3] & 0x02)
ef416fc2 1853 {
1854 /*
1855 * Skip header CRC data...
1856 */
1857
1858 ptr += 2;
1859
1860 if (ptr > end)
1861 {
1862 /*
1863 * Can't read from file!
1864 */
1865
1866 return (-1);
1867 }
1868 }
1869
fa73b229 1870 /*
1871 * Copy the flate-compressed data to the compression buffer...
1872 */
1873
1874 if ((bytes = end - ptr) > 0)
1875 memcpy(fp->cbuf, ptr, bytes);
1876
ef416fc2 1877 /*
1878 * Setup the decompressor data...
1879 */
1880
1881 fp->stream.zalloc = (alloc_func)0;
1882 fp->stream.zfree = (free_func)0;
1883 fp->stream.opaque = (voidpf)0;
fa73b229 1884 fp->stream.next_in = (Bytef *)fp->cbuf;
ef416fc2 1885 fp->stream.next_out = NULL;
fa73b229 1886 fp->stream.avail_in = bytes;
ef416fc2 1887 fp->stream.avail_out = 0;
1888 fp->crc = crc32(0L, Z_NULL, 0);
1889
1890 if (inflateInit2(&(fp->stream), -15) != Z_OK)
1891 return (-1);
1892
1893 fp->compressed = 1;
1894 }
1895
1896 if (fp->compressed)
1897 {
1898 /*
1899 * If we have reached end-of-file, return immediately...
1900 */
1901
1902 if (fp->eof)
1903 return (-1);
1904
1905 /*
1906 * Fill the decompression buffer as needed...
1907 */
1908
1909 if (fp->stream.avail_in == 0)
1910 {
1911 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1912 return (-1);
1913
1914 fp->stream.next_in = fp->cbuf;
1915 fp->stream.avail_in = bytes;
1916 }
1917
1918 /*
1919 * Decompress data from the buffer...
1920 */
1921
1922 fp->stream.next_out = (Bytef *)fp->buf;
1923 fp->stream.avail_out = sizeof(fp->buf);
1924
c277e2f8
MS
1925 status = inflate(&(fp->stream), Z_NO_FLUSH);
1926
1927 if (fp->stream.next_out > (Bytef *)fp->buf)
1928 fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
1929 fp->stream.next_out - (Bytef *)fp->buf);
1930
1931 if (status == Z_STREAM_END)
ef416fc2 1932 {
1933 /*
1934 * Read the CRC and length...
1935 */
1936
1937 unsigned char trailer[8]; /* Trailer bytes */
1938 uLong tcrc; /* Trailer CRC */
1939
1940
1941 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
1942 {
1943 /*
1944 * Can't get it, so mark end-of-file...
1945 */
1946
1947 fp->eof = 1;
ef416fc2 1948 }
fa73b229 1949 else
1950 {
1951 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
1952 trailer[0];
ef416fc2 1953
fa73b229 1954 if (tcrc != fp->crc)
1955 {
1956 /*
1957 * Bad CRC, mark end-of-file...
1958 */
1959
c277e2f8
MS
1960 DEBUG_printf(("cups_fill: tcrc=%08x, fp->crc=%08x\n",
1961 (unsigned int)tcrc, (unsigned int)fp->crc));
1962
fa73b229 1963 fp->eof = 1;
1964
1965 return (-1);
1966 }
ef416fc2 1967
ef416fc2 1968 /*
fa73b229 1969 * Otherwise, reset the compressed flag so that we re-read the
1970 * file header...
ef416fc2 1971 */
ef416fc2 1972
fa73b229 1973 fp->compressed = 0;
ef416fc2 1974 }
ef416fc2 1975 }
1976
1977 bytes = sizeof(fp->buf) - fp->stream.avail_out;
1978
1979 /*
1980 * Return the decompressed data...
1981 */
1982
1983 fp->ptr = fp->buf;
1984 fp->end = fp->buf + bytes;
1985
fa73b229 1986 if (bytes)
1987 return (bytes);
ef416fc2 1988 }
1989 }
1990#endif /* HAVE_LIBZ */
1991
1992 /*
1993 * Read a buffer's full of data...
1994 */
1995
1996 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1997 {
1998 /*
1999 * Can't read from file!
2000 */
2001
2002 fp->eof = 1;
2003 fp->ptr = fp->buf;
2004 fp->end = fp->buf;
2005
2006 return (-1);
2007 }
2008
2009 /*
2010 * Return the bytes we read...
2011 */
2012
2013 fp->eof = 0;
2014 fp->ptr = fp->buf;
2015 fp->end = fp->buf + bytes;
2016
2017 return (bytes);
2018}
2019
2020
2021/*
2022 * 'cups_read()' - Read from a file descriptor.
2023 */
2024
2025static ssize_t /* O - Number of bytes read or -1 */
2026cups_read(cups_file_t *fp, /* I - CUPS file */
2027 char *buf, /* I - Buffer */
2028 size_t bytes) /* I - Number bytes */
2029{
2030 ssize_t total; /* Total bytes read */
2031
2032
2033 /*
2034 * Loop until we read at least 0 bytes...
2035 */
2036
2037 for (;;)
2038 {
b86bc4cf 2039#ifdef WIN32
2040 if (fp->mode == 's')
2041 total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2042 else
2043 total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2044#else
ef416fc2 2045 if (fp->mode == 's')
2046 total = recv(fp->fd, buf, bytes, 0);
2047 else
2048 total = read(fp->fd, buf, bytes);
b86bc4cf 2049#endif /* WIN32 */
ef416fc2 2050
2051 if (total >= 0)
2052 break;
2053
2054 /*
2055 * Reads can be interrupted by signals and unavailable resources...
2056 */
2057
2058 if (errno == EAGAIN || errno == EINTR)
2059 continue;
2060 else
2061 return (-1);
2062 }
2063
2064 /*
2065 * Return the total number of bytes read...
2066 */
2067
2068 return (total);
2069}
2070
2071
2072/*
2073 * 'cups_write()' - Write to a file descriptor.
2074 */
2075
2076static ssize_t /* O - Number of bytes written or -1 */
2077cups_write(cups_file_t *fp, /* I - CUPS file */
2078 const char *buf, /* I - Buffer */
2079 size_t bytes) /* I - Number bytes */
2080{
2abf387c 2081 size_t total; /* Total bytes written */
2082 ssize_t count; /* Count this time */
ef416fc2 2083
2084
ecdc0628 2085 DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
2086 (long)bytes));
2087
ef416fc2 2088 /*
2089 * Loop until all bytes are written...
2090 */
2091
2092 total = 0;
2093 while (bytes > 0)
2094 {
b86bc4cf 2095#ifdef WIN32
2096 if (fp->mode == 's')
2097 count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2098 else
2099 count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2100#else
ef416fc2 2101 if (fp->mode == 's')
2102 count = send(fp->fd, buf, bytes, 0);
2103 else
2104 count = write(fp->fd, buf, bytes);
b86bc4cf 2105#endif /* WIN32 */
ef416fc2 2106
2107 if (count < 0)
2108 {
2109 /*
2110 * Writes can be interrupted by signals and unavailable resources...
2111 */
2112
2113 if (errno == EAGAIN || errno == EINTR)
2114 continue;
2115 else
2116 return (-1);
2117 }
2118
ecdc0628 2119 DEBUG_printf((" count=%ld\n", (long)count));
2120
ef416fc2 2121 /*
2122 * Update the counts for the last write call...
2123 */
2124
2125 bytes -= count;
2126 total += count;
2127 buf += count;
2128 }
2129
2130 /*
2131 * Return the total number of bytes written...
2132 */
2133
b86bc4cf 2134 return ((ssize_t)total);
ef416fc2 2135}
2136
2137
2138/*
2e4ff8af 2139 * End of "$Id: file.c 6962 2007-09-17 20:35:47Z mike $".
ef416fc2 2140 */