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