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