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