]> 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/*
b86bc4cf 2 * "$Id: file.c 6193 2007-01-10 19:27:04Z 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;
511
512 while (cupsFileGets(fp, buf, buflen))
513 {
514 (*linenum) ++;
515
516 /*
517 * Strip any comments...
518 */
519
520 if ((ptr = strchr(buf, '#')) != NULL)
521 {
522 while (ptr > buf)
523 {
524 if (!isspace(ptr[-1] & 255))
525 break;
526
527 ptr --;
528 }
529
530 *ptr = '\0';
531 }
532
533 /*
534 * Strip leading whitespace...
535 */
536
537 for (ptr = buf; isspace(*ptr & 255); ptr ++);
538
539 if (ptr > buf)
540 _cups_strcpy(buf, ptr);
541
542 /*
543 * See if there is anything left...
544 */
545
546 if (buf[0])
547 {
548 /*
549 * Yes, grab any value and return...
550 */
551
552 for (ptr = buf; *ptr; ptr ++)
553 if (isspace(*ptr & 255))
554 break;
555
556 if (*ptr)
557 {
558 /*
559 * Have a value, skip any other spaces...
560 */
561
562 while (isspace(*ptr & 255))
563 *ptr++ = '\0';
564
565 if (*ptr)
566 *value = ptr;
567
568 /*
569 * Strip trailing whitespace and > for lines that begin with <...
570 */
571
572 ptr += strlen(ptr) - 1;
573
574 if (buf[0] == '<' && *ptr == '>')
575 *ptr-- = '\0';
576 else if (buf[0] == '<' && *ptr != '>')
577 {
578 /*
579 * Syntax error...
580 */
581
582 *value = NULL;
583 return (buf);
584 }
585
586 while (ptr > *value && isspace(*ptr & 255))
587 *ptr-- = '\0';
588 }
589
590 /*
591 * Return the line...
592 */
593
594 return (buf);
595 }
596 }
597
598 return (NULL);
599}
600
601
80ca4592 602/*
603 * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
604 * contain binary data.
605 *
606 * This function differs from cupsFileGets() in that the trailing CR and LF
607 * are preserved, as is any binary data on the line. The buffer is nul-
608 * terminated, however you should use the returned length to determine
609 * the number of bytes on the line.
610 */
611
612size_t /* O - Number of bytes on line or 0 on EOF */
613cupsFileGetLine(cups_file_t *fp, /* I - File to read from */
614 char *buf, /* I - Buffer */
615 size_t buflen) /* I - Size of buffer */
616{
617 int ch; /* Character from file */
618 char *ptr, /* Current position in line buffer */
619 *end; /* End of line buffer */
620
621
622 /*
623 * Range check input...
624 */
625
626 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
627 return (0);
628
629 /*
630 * Now loop until we have a valid line...
631 */
632
633 for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
634 {
635 if (fp->ptr >= fp->end)
636 if (cups_fill(fp) <= 0)
637 break;
638
639 *ptr++ = ch = *(fp->ptr)++;
640
641 if (ch == '\r')
642 {
643 /*
644 * Check for CR LF...
645 */
646
647 if (fp->ptr >= fp->end)
648 if (cups_fill(fp) <= 0)
649 break;
650
651 if (*(fp->ptr) == '\n')
652 *ptr++ = *(fp->ptr)++;
653
654 break;
655 }
656 else if (ch == '\n')
657 {
658 /*
659 * Line feed ends a line...
660 */
661
662 break;
663 }
664 }
665
666 *ptr = '\0';
667
668 return (ptr - buf);
669}
670
671
ef416fc2 672/*
673 * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
674 */
675
676char * /* O - Line read or NULL on eof/error */
677cupsFileGets(cups_file_t *fp, /* I - CUPS file */
678 char *buf, /* O - String buffer */
679 size_t buflen) /* I - Size of string buffer */
680{
681 int ch; /* Character from file */
682 char *ptr, /* Current position in line buffer */
683 *end; /* End of line buffer */
684
685
686 /*
687 * Range check input...
688 */
689
690 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
691 return (NULL);
692
693 /*
694 * Now loop until we have a valid line...
695 */
696
697 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
698 {
699 if (fp->ptr >= fp->end)
700 if (cups_fill(fp) <= 0)
701 {
702 if (ptr == buf)
703 return (NULL);
704 else
705 break;
706 }
707
708 ch = *(fp->ptr)++;
709
710 if (ch == '\r')
711 {
712 /*
713 * Check for CR LF...
714 */
715
716 if (fp->ptr >= fp->end)
717 if (cups_fill(fp) <= 0)
718 break;
719
720 if (*(fp->ptr) == '\n')
721 fp->ptr ++;
722
723 break;
724 }
725 else if (ch == '\n')
726 {
727 /*
728 * Line feed ends a line...
729 */
730
731 break;
732 }
733 else
734 *ptr++ = ch;
735 }
736
737 *ptr = '\0';
738
739 return (buf);
740}
741
742
743/*
744 * 'cupsFileLock()' - Temporarily lock access to a file.
745 */
746
747int /* O - 0 on success, -1 on error */
748cupsFileLock(cups_file_t *fp, /* I - File to lock */
749 int block) /* I - 1 to wait for the lock, 0 to fail right away */
750{
751 /*
752 * Range check...
753 */
754
755 if (!fp || fp->mode == 's')
756 return (-1);
757
758 /*
759 * Try the lock...
760 */
761
762#ifdef WIN32
763 return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
764#else
765 return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
766#endif /* WIN32 */
767}
768
769
770/*
771 * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
772 */
773
774int /* O - File descriptor */
775cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
776{
777 return (fp->fd);
778}
779
780
781/*
782 * 'cupsFileOpen()' - Open a CUPS file.
783 */
784
785cups_file_t * /* O - CUPS file or NULL */
786cupsFileOpen(const char *filename, /* I - Name of file */
787 const char *mode) /* I - Open mode */
788{
789 cups_file_t *fp; /* New CUPS file */
790 int fd; /* File descriptor */
791 char hostname[1024], /* Hostname */
792 *portname; /* Port "name" (number or service) */
793 http_addrlist_t *addrlist; /* Host address list */
794
795
b423cd4c 796 DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")\n", filename,
797 mode));
798
ef416fc2 799 /*
800 * Range check input...
801 */
802
803 if (!filename || !mode ||
804 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
805 return (NULL);
806
807 /*
808 * Open the file...
809 */
810
811 switch (*mode)
812 {
813 case 'a' : /* Append file */
b86bc4cf 814 fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY, 0666);
ef416fc2 815 break;
816
817 case 'r' : /* Read file */
b86bc4cf 818 fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
ef416fc2 819 break;
820
821 case 'w' : /* Write file */
b86bc4cf 822 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE | O_BINARY, 0666);
ef416fc2 823 break;
824
825 case 's' : /* Read/write socket */
826 strlcpy(hostname, filename, sizeof(hostname));
827 if ((portname = strrchr(hostname, ':')) != NULL)
828 *portname++ = '\0';
829 else
830 return (NULL);
831
832 /*
833 * Lookup the hostname and service...
834 */
835
836 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
837 return (NULL);
838
839 /*
840 * Connect to the server...
841 */
842
843 if (!httpAddrConnect(addrlist, &fd))
844 {
845 httpAddrFreeList(addrlist);
846 return (NULL);
847 }
848
849 httpAddrFreeList(addrlist);
850 break;
851
852 default : /* Remove bogus compiler warning... */
853 return (NULL);
854 }
855
856 if (fd < 0)
857 return (NULL);
858
859 /*
860 * Create the CUPS file structure...
861 */
862
863 if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
864 {
865 if (*mode == 's')
866 closesocket(fd);
867 else
868 close(fd);
869 }
870
871 /*
872 * Return it...
873 */
874
875 return (fp);
876}
877
878/*
879 * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
880 */
881
882cups_file_t * /* O - CUPS file or NULL */
883cupsFileOpenFd(int fd, /* I - File descriptor */
884 const char *mode) /* I - Open mode */
885{
886 cups_file_t *fp; /* New CUPS file */
887
888
b423cd4c 889 DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")\n", fd, mode));
890
ef416fc2 891 /*
892 * Range check input...
893 */
894
895 if (fd < 0 || !mode ||
896 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
897 return (NULL);
898
899 /*
900 * Allocate memory...
901 */
902
903 if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
904 return (NULL);
905
906 /*
907 * Open the file...
908 */
909
910 fp->fd = fd;
911
912 switch (*mode)
913 {
914 case 'w' :
915 case 'a' :
916 fp->mode = 'w';
917 fp->ptr = fp->buf;
918 fp->end = fp->buf + sizeof(fp->buf);
919
920#ifdef HAVE_LIBZ
921 if (mode[1] >= '1' && mode[1] <= '9')
922 {
923 /*
924 * Open a compressed stream, so write the standard gzip file
925 * header...
926 */
927
928 unsigned char header[10]; /* gzip file header */
929 time_t curtime; /* Current time */
930
931
932 curtime = time(NULL);
933 header[0] = 0x1f;
934 header[1] = 0x8b;
935 header[2] = Z_DEFLATED;
936 header[3] = 0;
937 header[4] = curtime;
938 header[5] = curtime >> 8;
939 header[6] = curtime >> 16;
940 header[7] = curtime >> 24;
941 header[8] = 0;
942 header[9] = 0x03;
943
944 cups_write(fp, (char *)header, 10);
945
946 /*
947 * Initialize the compressor...
948 */
949
950 deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
951 Z_DEFAULT_STRATEGY);
952
953 fp->stream.next_out = fp->cbuf;
954 fp->stream.avail_out = sizeof(fp->cbuf);
955 fp->compressed = 1;
956 fp->crc = crc32(0L, Z_NULL, 0);
957 }
958#endif /* HAVE_LIBZ */
959 break;
960
961 case 'r' :
962 fp->mode = 'r';
963 break;
964
965 case 's' :
966 fp->mode = 's';
967 break;
968
969 default : /* Remove bogus compiler warning... */
970 return (NULL);
971 }
972
973 /*
974 * Don't pass this file to child processes...
975 */
976
977#ifndef WIN32
978 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
979#endif /* !WIN32 */
980
981 return (fp);
982}
983
984
985/*
986 * 'cupsFilePeekChar()' - Peek at the next character from a file.
987 */
988
989int /* O - Character or -1 on EOF */
990cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
991{
992 /*
993 * Range check input...
994 */
995
996 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
997 return (-1);
998
999 /*
1000 * If the input buffer is empty, try to read more data...
1001 */
1002
1003 if (fp->ptr >= fp->end)
1004 if (cups_fill(fp) < 0)
1005 return (-1);
1006
1007 /*
1008 * Return the next character in the buffer...
1009 */
1010
1011 return (*(fp->ptr) & 255);
1012}
1013
1014
1015/*
1016 * 'cupsFilePrintf()' - Write a formatted string.
1017 */
1018
1019int /* O - Number of bytes written or -1 */
1020cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
1021 const char *format, /* I - Printf-style format string */
1022 ...) /* I - Additional args as necessary */
1023{
1024 va_list ap; /* Argument list */
2abf387c 1025 ssize_t bytes; /* Formatted size */
ecdc0628 1026 char buf[8192]; /* Formatted text */
1027
ef416fc2 1028
ecdc0628 1029 DEBUG_printf(("cupsFilePrintf(fp=%p, format=\"%s\", ...)\n", fp, format));
ef416fc2 1030
1031 if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1032 return (-1);
1033
1034 va_start(ap, format);
1035 bytes = vsnprintf(buf, sizeof(buf), format, ap);
1036 va_end(ap);
1037
ecdc0628 1038 if (bytes >= sizeof(buf))
1039 return (-1);
1040
ef416fc2 1041 if (fp->mode == 's')
1042 return (cups_write(fp, buf, bytes));
1043
1044 if ((fp->ptr + bytes) > fp->end)
1045 if (cupsFileFlush(fp))
1046 return (-1);
1047
1048 fp->pos += bytes;
1049
1050 if (bytes > sizeof(fp->buf))
1051 {
1052#ifdef HAVE_LIBZ
1053 if (fp->compressed)
1054 return (cups_compress(fp, buf, bytes));
1055 else
1056#endif /* HAVE_LIBZ */
1057 return (cups_write(fp, buf, bytes));
1058 }
1059 else
1060 {
1061 memcpy(fp->ptr, buf, bytes);
1062 fp->ptr += bytes;
1063 return (bytes);
1064 }
1065}
1066
1067
1068/*
1069 * 'cupsFilePutChar()' - Write a character.
1070 */
1071
1072int /* O - 0 on success, -1 on error */
1073cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
1074 int c) /* I - Character to write */
1075{
1076 /*
1077 * Range check input...
1078 */
1079
1080 if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1081 return (-1);
1082
1083 if (fp->mode == 's')
1084 {
1085 /*
1086 * Send character immediately over socket...
1087 */
1088
1089 char ch; /* Output character */
1090
1091
1092 ch = c;
1093
1094 if (send(fp->fd, &ch, 1, 0) < 1)
1095 return (-1);
1096 }
1097 else
1098 {
1099 /*
1100 * Buffer it up...
1101 */
1102
1103 if (fp->ptr >= fp->end)
1104 if (cupsFileFlush(fp))
1105 return (-1);
1106
1107 *(fp->ptr) ++ = c;
1108 }
1109
1110 fp->pos ++;
1111
1112 return (0);
1113}
1114
1115
1116/*
1117 * 'cupsFilePuts()' - Write a string.
1118 */
1119
1120int /* O - Number of bytes written or -1 */
1121cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
1122 const char *s) /* I - String to write */
1123{
2abf387c 1124 ssize_t bytes; /* Bytes to write */
ef416fc2 1125
1126
1127 /*
1128 * Range check input...
1129 */
1130
1131 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1132 return (-1);
1133
1134 /*
1135 * Write the string...
1136 */
1137
b86bc4cf 1138 bytes = (int)strlen(s);
ef416fc2 1139
1140 if (fp->mode == 's')
1141 {
1142 if (cups_write(fp, s, bytes) < 0)
1143 return (-1);
1144
1145 fp->pos += bytes;
1146
1147 return (bytes);
1148 }
1149
1150 if ((fp->ptr + bytes) > fp->end)
1151 if (cupsFileFlush(fp))
1152 return (-1);
1153
1154 fp->pos += bytes;
1155
1156 if (bytes > sizeof(fp->buf))
1157 {
1158#ifdef HAVE_LIBZ
1159 if (fp->compressed)
1160 return (cups_compress(fp, s, bytes));
1161 else
1162#endif /* HAVE_LIBZ */
1163 return (cups_write(fp, s, bytes));
1164 }
1165 else
1166 {
1167 memcpy(fp->ptr, s, bytes);
1168 fp->ptr += bytes;
1169 return (bytes);
1170 }
1171}
1172
1173
1174/*
1175 * 'cupsFileRead()' - Read from a file.
1176 */
1177
1178ssize_t /* O - Number of bytes read or -1 */
1179cupsFileRead(cups_file_t *fp, /* I - CUPS file */
1180 char *buf, /* O - Buffer */
1181 size_t bytes) /* I - Number of bytes to read */
1182{
2abf387c 1183 size_t total; /* Total bytes read */
1184 ssize_t count; /* Bytes read */
ef416fc2 1185
1186
1187 DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1188 (long)bytes));
1189
1190 /*
1191 * Range check input...
1192 */
1193
1194 if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
1195 return (-1);
1196
1197 if (bytes == 0)
1198 return (0);
1199
1200 /*
1201 * Loop until all bytes are read...
1202 */
1203
1204 total = 0;
1205 while (bytes > 0)
1206 {
1207 if (fp->ptr >= fp->end)
1208 if (cups_fill(fp) <= 0)
1209 {
1210 DEBUG_printf((" cups_fill() returned -1, total=%d\n", total));
1211
1212 if (total > 0)
b86bc4cf 1213 return ((ssize_t)total);
ef416fc2 1214 else
1215 return (-1);
1216 }
1217
b86bc4cf 1218 count = (ssize_t)(fp->end - fp->ptr);
1219 if (count > (ssize_t)bytes)
1220 count = (ssize_t)bytes;
ef416fc2 1221
1222 memcpy(buf, fp->ptr, count);
1223 fp->ptr += count;
1224
1225 /*
1226 * Update the counts for the last read...
1227 */
1228
1229 bytes -= count;
1230 total += count;
1231 buf += count;
1232 }
1233
1234 /*
1235 * Return the total number of bytes read...
1236 */
1237
1238 DEBUG_printf((" total=%d\n", total));
1239
b86bc4cf 1240 return ((ssize_t)total);
ef416fc2 1241}
1242
1243
1244/*
1245 * 'cupsFileRewind()' - Rewind a file.
1246 */
1247
1248off_t /* O - New file position or -1 */
1249cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
1250{
80ca4592 1251 /*
1252 * Range check input...
1253 */
1254
1255 if (!fp || fp->mode != 'r')
1256 return (-1);
1257
1258 /*
1259 * Handle special cases...
1260 */
1261
1262 if (fp->pos == 0)
1263 {
1264 /*
1265 * No seeking necessary...
1266 */
1267
1268 if (fp->ptr)
1269 {
1270 fp->ptr = fp->buf;
1271 fp->eof = 0;
1272 }
1273
1274 return (0);
1275 }
1276
1277 /*
1278 * Otherwise, seek in the file and cleanup any compression buffers...
1279 */
1280
1281#ifdef HAVE_LIBZ
1282 if (fp->compressed)
1283 {
1284 inflateEnd(&fp->stream);
1285 fp->compressed = 0;
1286 }
1287#endif /* HAVE_LIBZ */
1288
1289 lseek(fp->fd, 0, SEEK_SET);
1290
1291 fp->pos = 0;
1292 fp->ptr = NULL;
1293 fp->end = NULL;
d09495fa 1294 fp->eof = 0;
80ca4592 1295
1296 return (0);
ef416fc2 1297}
1298
1299
1300/*
1301 * 'cupsFileSeek()' - Seek in a file.
1302 */
1303
1304off_t /* O - New file position or -1 */
1305cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
1306 off_t pos) /* I - Position in file */
1307{
2abf387c 1308 ssize_t bytes; /* Number bytes in buffer */
ef416fc2 1309
1310
b423cd4c 1311 DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")\n", fp, pos));
1312 DEBUG_printf((" fp->pos=" CUPS_LLFMT "\n", fp->pos));
1313 DEBUG_printf((" fp->ptr=%p, fp->end=%p\n", fp->ptr, fp->end));
ef416fc2 1314
1315 /*
1316 * Range check input...
1317 */
1318
1319 if (!fp || pos < 0 || fp->mode != 'r')
1320 return (-1);
1321
80ca4592 1322 /*
1323 * Handle special cases...
1324 */
1325
1326 if (pos == 0)
1327 return (cupsFileRewind(fp));
1328
b423cd4c 1329 if (fp->pos == pos)
1330 {
1331 /*
1332 * No seeking necessary...
1333 */
1334
1335 if (fp->ptr)
1336 {
1337 fp->ptr = fp->buf;
1338 fp->eof = 0;
1339 }
1340
1341 return (pos);
1342 }
1343
80ca4592 1344#ifdef HAVE_LIBZ
1345 if (!fp->compressed && !fp->ptr)
1346 {
1347 /*
1348 * Preload a buffer to determine whether the file is compressed...
1349 */
1350
1351 if (cups_fill(fp) < 0)
1352 return (-1);
1353 }
1354#endif /* HAVE_LIBZ */
1355
ef416fc2 1356 /*
1357 * Figure out the number of bytes in the current buffer, and then
1358 * see if we are outside of it...
1359 */
1360
80ca4592 1361 if (fp->ptr)
b86bc4cf 1362 bytes = (ssize_t)(fp->end - fp->buf);
80ca4592 1363 else
1364 bytes = 0;
1365
ef416fc2 1366 fp->eof = 0;
1367
80ca4592 1368 DEBUG_printf((" bytes=" CUPS_LLFMT "\n", CUPS_LLCAST bytes));
1369
ef416fc2 1370 if (pos < fp->pos)
1371 {
1372 /*
1373 * Need to seek backwards...
1374 */
1375
80ca4592 1376 DEBUG_puts(" SEEK BACKWARDS");
1377
ef416fc2 1378#ifdef HAVE_LIBZ
1379 if (fp->compressed)
1380 {
1381 inflateEnd(&fp->stream);
1382
1383 lseek(fp->fd, 0, SEEK_SET);
1384 fp->pos = 0;
1385 fp->ptr = NULL;
1386 fp->end = NULL;
1387
1388 while ((bytes = cups_fill(fp)) > 0)
1389 if (pos >= fp->pos && pos < (fp->pos + bytes))
1390 break;
1391
1392 if (bytes <= 0)
1393 return (-1);
80ca4592 1394
1395 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1396 }
1397 else
1398#endif /* HAVE_LIBZ */
1399 {
1400 fp->pos = lseek(fp->fd, pos, SEEK_SET);
ef416fc2 1401 fp->ptr = NULL;
1402 fp->end = NULL;
80ca4592 1403
1404 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
ef416fc2 1405 }
1406 }
1407 else if (pos >= (fp->pos + bytes))
1408 {
1409 /*
1410 * Need to seek forwards...
1411 */
1412
80ca4592 1413 DEBUG_puts(" SEEK FORWARDS");
1414
ef416fc2 1415#ifdef HAVE_LIBZ
80ca4592 1416 if (fp->compressed)
ef416fc2 1417 {
1418 while ((bytes = cups_fill(fp)) > 0)
80ca4592 1419 {
ef416fc2 1420 if (pos >= fp->pos && pos < (fp->pos + bytes))
1421 break;
80ca4592 1422 }
ef416fc2 1423
1424 if (bytes <= 0)
1425 return (-1);
80ca4592 1426
1427 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1428 }
1429 else
1430#endif /* HAVE_LIBZ */
1431 {
1432 fp->pos = lseek(fp->fd, pos, SEEK_SET);
ef416fc2 1433 fp->ptr = NULL;
1434 fp->end = NULL;
80ca4592 1435
1436 DEBUG_printf((" lseek() returned " CUPS_LLFMT "...\n", fp->pos));
ef416fc2 1437 }
1438 }
1439 else
1440 {
1441 /*
1442 * Just reposition the current pointer, since we have the right
1443 * range...
1444 */
1445
80ca4592 1446 DEBUG_puts(" SEEK INSIDE BUFFER");
1447
ef416fc2 1448 fp->ptr = fp->buf + pos - fp->pos;
ef416fc2 1449 }
1450
1451 return (fp->pos);
1452}
1453
1454
80ca4592 1455/*
1456 * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
1457 */
1458
1459cups_file_t *
1460cupsFileStderr(void)
1461{
1462 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1463
1464
1465 /*
1466 * Open file descriptor 2 as needed...
1467 */
1468
1469 if (!cg->stdio_files[2])
1470 {
1471 /*
1472 * Flush any pending output on the stdio file...
1473 */
1474
1475 fflush(stderr);
1476
1477 /*
1478 * Open file descriptor 2...
1479 */
1480
1481 if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1482 cg->stdio_files[2]->is_stdio = 1;
1483 }
1484
1485 return (cg->stdio_files[2]);
1486}
1487
1488
1489/*
1490 * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
1491 */
1492
1493cups_file_t *
1494cupsFileStdin(void)
1495{
1496 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1497
1498
1499 /*
1500 * Open file descriptor 0 as needed...
1501 */
1502
1503 if (!cg->stdio_files[0])
1504 {
1505 /*
1506 * Open file descriptor 0...
1507 */
1508
1509 if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1510 cg->stdio_files[0]->is_stdio = 1;
1511 }
1512
1513 return (cg->stdio_files[0]);
1514}
1515
1516
1517/*
1518 * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
1519 */
1520
1521cups_file_t *
1522cupsFileStdout(void)
1523{
1524 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1525
1526
1527 /*
1528 * Open file descriptor 1 as needed...
1529 */
1530
1531 if (!cg->stdio_files[1])
1532 {
1533 /*
1534 * Flush any pending output on the stdio file...
1535 */
1536
1537 fflush(stdout);
1538
1539 /*
1540 * Open file descriptor 1...
1541 */
1542
1543 if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
1544 cg->stdio_files[1]->is_stdio = 1;
1545 }
1546
1547 return (cg->stdio_files[1]);
1548}
1549
1550
ef416fc2 1551/*
1552 * 'cupsFileTell()' - Return the current file position.
1553 */
1554
1555off_t /* O - File position */
1556cupsFileTell(cups_file_t *fp) /* I - CUPS file */
1557{
80ca4592 1558 return (fp ? fp->pos : 0);
ef416fc2 1559}
1560
1561
1562/*
1563 * 'cupsFileUnlock()' - Unlock access to a file.
1564 */
1565
1566int /* O - 0 on success, -1 on error */
1567cupsFileUnlock(cups_file_t *fp) /* I - File to lock */
1568{
1569 /*
1570 * Range check...
1571 */
1572
1573 if (!fp || fp->mode == 's')
1574 return (-1);
1575
1576 /*
1577 * Unlock...
1578 */
1579
1580#ifdef WIN32
1581 return (locking(fp->fd, _LK_UNLCK, 0));
1582#else
1583 return (lockf(fp->fd, F_ULOCK, 0));
1584#endif /* WIN32 */
1585}
1586
1587
1588/*
1589 * 'cupsFileWrite()' - Write to a file.
1590 */
1591
1592ssize_t /* O - Number of bytes written */
1593cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
1594 const char *buf, /* I - Buffer */
1595 size_t bytes) /* I - Number of bytes to write */
1596{
1597 /*
1598 * Range check input...
1599 */
1600
1601 if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
1602 return (-1);
1603
1604 if (bytes == 0)
1605 return (0);
1606
1607 /*
1608 * Write the buffer...
1609 */
1610
1611 if (fp->mode == 's')
1612 {
1613 if (cups_write(fp, buf, bytes) < 0)
1614 return (-1);
1615
b86bc4cf 1616 fp->pos += (off_t)bytes;
ef416fc2 1617
b86bc4cf 1618 return ((ssize_t)bytes);
ef416fc2 1619 }
1620
1621 if ((fp->ptr + bytes) > fp->end)
1622 if (cupsFileFlush(fp))
1623 return (-1);
1624
b86bc4cf 1625 fp->pos += (off_t)bytes;
ef416fc2 1626
1627 if (bytes > sizeof(fp->buf))
1628 {
1629#ifdef HAVE_LIBZ
1630 if (fp->compressed)
1631 return (cups_compress(fp, buf, bytes));
1632 else
1633#endif /* HAVE_LIBZ */
1634 return (cups_write(fp, buf, bytes));
1635 }
1636 else
1637 {
1638 memcpy(fp->ptr, buf, bytes);
1639 fp->ptr += bytes;
b86bc4cf 1640 return ((ssize_t)bytes);
ef416fc2 1641 }
1642}
1643
1644
1645#ifdef HAVE_LIBZ
1646/*
1647 * 'cups_compress()' - Compress a buffer of data...
1648 */
1649
1650static ssize_t /* O - Number of bytes written or -1 */
1651cups_compress(cups_file_t *fp, /* I - CUPS file */
1652 const char *buf, /* I - Buffer */
1653 size_t bytes) /* I - Number bytes */
1654{
ecdc0628 1655 DEBUG_printf(("cups_compress(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1656 (long)bytes));
1657
ef416fc2 1658 /*
1659 * Update the CRC...
1660 */
1661
1662 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
1663
1664 /*
1665 * Deflate the bytes...
1666 */
1667
1668 fp->stream.next_in = (Bytef *)buf;
1669 fp->stream.avail_in = bytes;
1670
1671 while (fp->stream.avail_in > 0)
1672 {
1673 /*
1674 * Flush the current buffer...
1675 */
1676
ecdc0628 1677 DEBUG_printf((" avail_in=%d, avail_out=%d\n", fp->stream.avail_in,
1678 fp->stream.avail_out));
1679
ef416fc2 1680 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
1681 {
1682 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
1683 return (-1);
ecdc0628 1684
1685 fp->stream.next_out = fp->cbuf;
1686 fp->stream.avail_out = sizeof(fp->cbuf);
ef416fc2 1687 }
1688
1689 deflate(&(fp->stream), Z_NO_FLUSH);
1690 }
1691
1692 return (bytes);
1693}
1694#endif /* HAVE_LIBZ */
1695
1696
1697/*
1698 * 'cups_fill()' - Fill the input buffer...
1699 */
1700
1701static ssize_t /* O - Number of bytes or -1 */
1702cups_fill(cups_file_t *fp) /* I - CUPS file */
1703{
1704 ssize_t bytes; /* Number of bytes read */
1705#ifdef HAVE_LIBZ
1706 const unsigned char *ptr, /* Pointer into buffer */
1707 *end; /* End of buffer */
1708#endif /* HAVE_LIBZ */
1709
1710
1711 DEBUG_printf(("cups_fill(fp=%p)\n", fp));
b423cd4c 1712 DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, "
1713 "fp->pos=" CUPS_LLFMT ", fp->eof=%d\n",
1714 fp->ptr, fp->end, fp->buf, fp->pos, fp->eof));
ef416fc2 1715
1716 /*
1717 * Update the "pos" element as needed...
1718 */
1719
1720 if (fp->ptr && fp->end)
b86bc4cf 1721 fp->pos += (off_t)(fp->end - fp->buf);
ef416fc2 1722
1723#ifdef HAVE_LIBZ
b423cd4c 1724 DEBUG_printf((" fp->compressed=%d\n", fp->compressed));
1725
ef416fc2 1726 while (!fp->ptr || fp->compressed)
1727 {
1728 /*
1729 * Check to see if we have read any data yet; if not, see if we have a
1730 * compressed file...
1731 */
1732
1733 if (!fp->ptr)
1734 {
1735 /*
1736 * Reset the file position in case we are seeking...
1737 */
1738
1739 fp->compressed = 0;
ef416fc2 1740
1741 /*
1742 * Read the first bytes in the file to determine if we have a gzip'd
1743 * file...
1744 */
1745
fa73b229 1746 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
ef416fc2 1747 {
1748 /*
1749 * Can't read from file!
1750 */
1751
b423cd4c 1752 DEBUG_printf((" cups_read() returned " CUPS_LLFMT "!\n",
1753 CUPS_LLCAST bytes));
1754
ef416fc2 1755 return (-1);
1756 }
1757
fa73b229 1758 if (bytes < 10 || fp->buf[0] != 0x1f ||
e00b005a 1759 (fp->buf[1] & 255) != 0x8b ||
fa73b229 1760 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
ef416fc2 1761 {
1762 /*
1763 * Not a gzip'd file!
1764 */
1765
ef416fc2 1766 fp->ptr = fp->buf;
1767 fp->end = fp->buf + bytes;
1768
b423cd4c 1769 DEBUG_printf((" returning " CUPS_LLFMT "!\n", CUPS_LLCAST bytes));
1770
ef416fc2 1771 return (bytes);
1772 }
1773
1774 /*
1775 * Parse header junk: extra data, original name, and comment...
1776 */
1777
fa73b229 1778 ptr = (unsigned char *)fp->buf + 10;
1779 end = (unsigned char *)fp->buf + bytes;
ef416fc2 1780
fa73b229 1781 if (fp->buf[3] & 0x04)
ef416fc2 1782 {
1783 /*
1784 * Skip extra data...
1785 */
1786
1787 if ((ptr + 2) > end)
1788 {
1789 /*
1790 * Can't read from file!
1791 */
1792
1793 return (-1);
1794 }
1795
1796 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1797 ptr += 2 + bytes;
1798
1799 if (ptr > end)
1800 {
1801 /*
1802 * Can't read from file!
1803 */
1804
1805 return (-1);
1806 }
1807 }
1808
fa73b229 1809 if (fp->buf[3] & 0x08)
ef416fc2 1810 {
1811 /*
1812 * Skip original name data...
1813 */
1814
1815 while (ptr < end && *ptr)
1816 ptr ++;
1817
1818 if (ptr < end)
1819 ptr ++;
1820 else
1821 {
1822 /*
1823 * Can't read from file!
1824 */
1825
1826 return (-1);
1827 }
1828 }
1829
fa73b229 1830 if (fp->buf[3] & 0x10)
ef416fc2 1831 {
1832 /*
1833 * Skip comment data...
1834 */
1835
1836 while (ptr < end && *ptr)
1837 ptr ++;
1838
1839 if (ptr < end)
1840 ptr ++;
1841 else
1842 {
1843 /*
1844 * Can't read from file!
1845 */
1846
1847 return (-1);
1848 }
1849 }
1850
fa73b229 1851 if (fp->buf[3] & 0x02)
ef416fc2 1852 {
1853 /*
1854 * Skip header CRC data...
1855 */
1856
1857 ptr += 2;
1858
1859 if (ptr > end)
1860 {
1861 /*
1862 * Can't read from file!
1863 */
1864
1865 return (-1);
1866 }
1867 }
1868
fa73b229 1869 /*
1870 * Copy the flate-compressed data to the compression buffer...
1871 */
1872
1873 if ((bytes = end - ptr) > 0)
1874 memcpy(fp->cbuf, ptr, bytes);
1875
ef416fc2 1876 /*
1877 * Setup the decompressor data...
1878 */
1879
1880 fp->stream.zalloc = (alloc_func)0;
1881 fp->stream.zfree = (free_func)0;
1882 fp->stream.opaque = (voidpf)0;
fa73b229 1883 fp->stream.next_in = (Bytef *)fp->cbuf;
ef416fc2 1884 fp->stream.next_out = NULL;
fa73b229 1885 fp->stream.avail_in = bytes;
ef416fc2 1886 fp->stream.avail_out = 0;
1887 fp->crc = crc32(0L, Z_NULL, 0);
1888
1889 if (inflateInit2(&(fp->stream), -15) != Z_OK)
1890 return (-1);
1891
1892 fp->compressed = 1;
1893 }
1894
1895 if (fp->compressed)
1896 {
1897 /*
1898 * If we have reached end-of-file, return immediately...
1899 */
1900
1901 if (fp->eof)
1902 return (-1);
1903
1904 /*
1905 * Fill the decompression buffer as needed...
1906 */
1907
1908 if (fp->stream.avail_in == 0)
1909 {
1910 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1911 return (-1);
1912
1913 fp->stream.next_in = fp->cbuf;
1914 fp->stream.avail_in = bytes;
1915 }
1916
1917 /*
1918 * Decompress data from the buffer...
1919 */
1920
1921 fp->stream.next_out = (Bytef *)fp->buf;
1922 fp->stream.avail_out = sizeof(fp->buf);
1923
1924 if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
1925 {
1926 /*
1927 * Read the CRC and length...
1928 */
1929
1930 unsigned char trailer[8]; /* Trailer bytes */
1931 uLong tcrc; /* Trailer CRC */
1932
1933
1934 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
1935 {
1936 /*
1937 * Can't get it, so mark end-of-file...
1938 */
1939
1940 fp->eof = 1;
ef416fc2 1941 }
fa73b229 1942 else
1943 {
1944 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
1945 trailer[0];
ef416fc2 1946
fa73b229 1947 if (tcrc != fp->crc)
1948 {
1949 /*
1950 * Bad CRC, mark end-of-file...
1951 */
1952
1953 fp->eof = 1;
1954
1955 return (-1);
1956 }
ef416fc2 1957
ef416fc2 1958 /*
fa73b229 1959 * Otherwise, reset the compressed flag so that we re-read the
1960 * file header...
ef416fc2 1961 */
ef416fc2 1962
fa73b229 1963 fp->compressed = 0;
ef416fc2 1964 }
ef416fc2 1965 }
1966
1967 bytes = sizeof(fp->buf) - fp->stream.avail_out;
1968
1969 /*
1970 * Return the decompressed data...
1971 */
1972
1973 fp->ptr = fp->buf;
1974 fp->end = fp->buf + bytes;
1975
fa73b229 1976 if (bytes)
1977 return (bytes);
ef416fc2 1978 }
1979 }
1980#endif /* HAVE_LIBZ */
1981
1982 /*
1983 * Read a buffer's full of data...
1984 */
1985
1986 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1987 {
1988 /*
1989 * Can't read from file!
1990 */
1991
1992 fp->eof = 1;
1993 fp->ptr = fp->buf;
1994 fp->end = fp->buf;
1995
1996 return (-1);
1997 }
1998
1999 /*
2000 * Return the bytes we read...
2001 */
2002
2003 fp->eof = 0;
2004 fp->ptr = fp->buf;
2005 fp->end = fp->buf + bytes;
2006
2007 return (bytes);
2008}
2009
2010
2011/*
2012 * 'cups_read()' - Read from a file descriptor.
2013 */
2014
2015static ssize_t /* O - Number of bytes read or -1 */
2016cups_read(cups_file_t *fp, /* I - CUPS file */
2017 char *buf, /* I - Buffer */
2018 size_t bytes) /* I - Number bytes */
2019{
2020 ssize_t total; /* Total bytes read */
2021
2022
2023 /*
2024 * Loop until we read at least 0 bytes...
2025 */
2026
2027 for (;;)
2028 {
b86bc4cf 2029#ifdef WIN32
2030 if (fp->mode == 's')
2031 total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2032 else
2033 total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2034#else
ef416fc2 2035 if (fp->mode == 's')
2036 total = recv(fp->fd, buf, bytes, 0);
2037 else
2038 total = read(fp->fd, buf, bytes);
b86bc4cf 2039#endif /* WIN32 */
ef416fc2 2040
2041 if (total >= 0)
2042 break;
2043
2044 /*
2045 * Reads can be interrupted by signals and unavailable resources...
2046 */
2047
2048 if (errno == EAGAIN || errno == EINTR)
2049 continue;
2050 else
2051 return (-1);
2052 }
2053
2054 /*
2055 * Return the total number of bytes read...
2056 */
2057
2058 return (total);
2059}
2060
2061
2062/*
2063 * 'cups_write()' - Write to a file descriptor.
2064 */
2065
2066static ssize_t /* O - Number of bytes written or -1 */
2067cups_write(cups_file_t *fp, /* I - CUPS file */
2068 const char *buf, /* I - Buffer */
2069 size_t bytes) /* I - Number bytes */
2070{
2abf387c 2071 size_t total; /* Total bytes written */
2072 ssize_t count; /* Count this time */
ef416fc2 2073
2074
ecdc0628 2075 DEBUG_printf(("cups_write(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
2076 (long)bytes));
2077
ef416fc2 2078 /*
2079 * Loop until all bytes are written...
2080 */
2081
2082 total = 0;
2083 while (bytes > 0)
2084 {
b86bc4cf 2085#ifdef WIN32
2086 if (fp->mode == 's')
2087 count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2088 else
2089 count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2090#else
ef416fc2 2091 if (fp->mode == 's')
2092 count = send(fp->fd, buf, bytes, 0);
2093 else
2094 count = write(fp->fd, buf, bytes);
b86bc4cf 2095#endif /* WIN32 */
ef416fc2 2096
2097 if (count < 0)
2098 {
2099 /*
2100 * Writes can be interrupted by signals and unavailable resources...
2101 */
2102
2103 if (errno == EAGAIN || errno == EINTR)
2104 continue;
2105 else
2106 return (-1);
2107 }
2108
ecdc0628 2109 DEBUG_printf((" count=%ld\n", (long)count));
2110
ef416fc2 2111 /*
2112 * Update the counts for the last write call...
2113 */
2114
2115 bytes -= count;
2116 total += count;
2117 buf += count;
2118 }
2119
2120 /*
2121 * Return the total number of bytes written...
2122 */
2123
b86bc4cf 2124 return ((ssize_t)total);
ef416fc2 2125}
2126
2127
2128/*
b86bc4cf 2129 * End of "$Id: file.c 6193 2007-01-10 19:27:04Z mike $".
ef416fc2 2130 */