]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/file.c
81f43a97d0f9a6a0d3e3d41bfa5a8ef41c756dd3
[thirdparty/cups.git] / cups / file.c
1 /*
2 * "$Id$"
3 *
4 * File functions for the Common UNIX Printing System (CUPS).
5 *
6 * Since stdio files max out at 256 files on many systems, we have to
7 * write similar functions without this limit. At the same time, using
8 * our own file functions allows us to provide transparent support of
9 * gzip'd print files, PPD files, etc.
10 *
11 * Copyright 1997-2005 by Easy Software Products, all rights reserved.
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.
34 * cupsFileFlush() - Flush pending output.
35 * cupsFileGetChar() - Get a single character from a file.
36 * cupsFileGetConf() - Get a line from a configuration file...
37 * cupsFileGets() - Get a CR and/or LF-terminated line.
38 * cupsFileLock() - Temporarily lock access to a file.
39 * cupsFileNumber() - Return the file descriptor associated with a CUPS file.
40 * cupsFileOpen() - Open a CUPS file.
41 * cupsFileOpenFd() - Open a CUPS file using a file descriptor.
42 * cupsFilePeekChar() - Peek at the next character from a file.
43 * cupsFilePrintf() - Write a formatted string.
44 * cupsFilePutChar() - Write a character.
45 * cupsFilePuts() - Write a string.
46 * cupsFileRead() - Read from a file.
47 * cupsFileRewind() - Rewind a file.
48 * cupsFileSeek() - Seek in a file.
49 * cupsFileTell() - Return the current file position.
50 * cupsFileUnlock() - Unlock access to a file.
51 * cupsFileWrite() - Write to a file.
52 * cups_compress() - Compress a buffer of data...
53 * cups_fill() - Fill the input buffer...
54 * cups_read() - Read from a file descriptor.
55 * cups_write() - Write to a file descriptor.
56 */
57
58 /*
59 * Include necessary headers...
60 */
61
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <stdarg.h>
65 #include "string.h"
66 #include <errno.h>
67 #include <cups/debug.h>
68 #include <sys/types.h>
69
70 #ifdef WIN32
71 # include <io.h>
72 # include <winsock2.h>
73 #else
74 # include <unistd.h>
75 # include <fcntl.h>
76 # include <sys/socket.h>
77 # define closesocket(f) close(f)
78 #endif /* WIN32 */
79
80 #include "file.h"
81 #ifdef HAVE_LIBZ
82 # include <zlib.h>
83 #endif /* HAVE_LIBZ */
84 #include "http-private.h"
85
86
87 /*
88 * Types and structures...
89 */
90 struct _cups_file_s /**** CUPS file structure... ****/
91
92 {
93 int fd; /* File descriptor */
94 char mode, /* Mode ('r' or 'w') */
95 compressed, /* Compression used? */
96 eof, /* End of file? */
97 buf[2048], /* Buffer */
98 *ptr, /* Pointer into buffer */
99 *end; /* End of buffer data */
100 off_t pos; /* File position for start of buffer */
101
102 #ifdef HAVE_LIBZ
103 z_stream stream; /* (De)compression stream */
104 Bytef cbuf[1024]; /* (De)compression buffer */
105 uLong crc; /* (De)compression CRC */
106 #endif /* HAVE_LIBZ */
107 };
108
109
110 /*
111 * Local functions...
112 */
113
114 #ifdef HAVE_LIBZ
115 static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
116 #endif /* HAVE_LIBZ */
117 static ssize_t cups_fill(cups_file_t *fp);
118 static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
119 static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
120
121
122 /*
123 * 'cupsFileClose()' - Close a CUPS file.
124 */
125
126 int /* O - 0 on success, -1 on error */
127 cupsFileClose(cups_file_t *fp) /* I - CUPS file */
128 {
129 int fd; /* File descriptor */
130 char mode; /* Open mode */
131 int status; /* Return status */
132
133
134 DEBUG_printf(("cupsFileClose(fp=%p)\n", fp));
135
136 /*
137 * Range check...
138 */
139
140 if (!fp)
141 return (-1);
142
143 /*
144 * Flush pending write data...
145 */
146
147 if (fp->mode == 'w')
148 status = cupsFileFlush(fp);
149 else
150 status = 0;
151
152 #ifdef HAVE_LIBZ
153 if (fp->compressed && status >= 0)
154 {
155 if (fp->mode == 'r')
156 {
157 /*
158 * Free decompression data...
159 */
160
161 inflateEnd(&fp->stream);
162 }
163 else
164 {
165 /*
166 * Flush any remaining compressed data...
167 */
168
169 unsigned char trailer[8]; /* Trailer CRC and length */
170 int done; /* Done writing... */
171
172
173 fp->stream.avail_in = 0;
174
175 for (done = 0;;)
176 {
177 if (fp->stream.next_out > fp->cbuf)
178 {
179 if (cups_write(fp, (char *)fp->cbuf,
180 fp->stream.next_out - fp->cbuf) < 0)
181 status = -1;
182
183 fp->stream.next_out = fp->cbuf;
184 fp->stream.avail_out = sizeof(fp->cbuf);
185 }
186
187 if (done || status < 0)
188 break;
189
190 done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
191 fp->stream.next_out == fp->cbuf;
192 }
193
194 /*
195 * Write the CRC and length...
196 */
197
198 trailer[0] = fp->crc;
199 trailer[1] = fp->crc >> 8;
200 trailer[2] = fp->crc >> 16;
201 trailer[3] = fp->crc >> 24;
202 trailer[4] = fp->pos;
203 trailer[5] = fp->pos >> 8;
204 trailer[6] = fp->pos >> 16;
205 trailer[7] = fp->pos >> 24;
206
207 if (cups_write(fp, (char *)trailer, 8) < 0)
208 status = -1;
209
210 /*
211 * Free all memory used by the compression stream...
212 */
213
214 deflateEnd(&(fp->stream));
215 }
216 }
217 #endif /* HAVE_LIBZ */
218
219 /*
220 * Save the file descriptor we used and free memory...
221 */
222
223 fd = fp->fd;
224 mode = fp->mode;
225
226 free(fp);
227
228 /*
229 * Close the file, returning the close status...
230 */
231
232 if (mode == 's')
233 {
234 if (closesocket(fd) < 0)
235 status = -1;
236 }
237 else
238 {
239 if (close(fd) < 0)
240 status = -1;
241 }
242
243 return (status);
244 }
245
246
247 /*
248 * 'cupsFileCompression()' - Return whether a file is compressed.
249 */
250
251 int /* O - CUPS_FILE_NONE or CUPS_FILE_GZIP */
252 cupsFileCompression(cups_file_t *fp) /* I - CUPS file */
253 {
254 return (fp->compressed);
255 }
256
257
258 /*
259 * 'cupsFileEOF()' - Return the end-of-file status.
260 */
261
262 int /* O - 1 on EOF, 0 otherwise */
263 cupsFileEOF(cups_file_t *fp) /* I - CUPS file */
264 {
265 return (fp->eof);
266 }
267
268
269 /*
270 * 'cupsFileFlush()' - Flush pending output.
271 */
272
273 int /* O - 0 on success, -1 on error */
274 cupsFileFlush(cups_file_t *fp) /* I - CUPS file */
275 {
276 size_t bytes; /* Bytes to write */
277
278
279 DEBUG_printf(("cupsFileFlush(fp=%p)\n", fp));
280
281 /*
282 * Range check input...
283 */
284
285 if (!fp || fp->mode != 'w')
286 {
287 DEBUG_puts(" Attempt to flush a read-only file...");
288 return (-1);
289 }
290
291 bytes = fp->ptr - fp->buf;
292
293 if (bytes > 0)
294 {
295 if (fp->compressed)
296 bytes = cups_compress(fp, fp->buf, bytes);
297 else
298 bytes = cups_write(fp, fp->buf, bytes);
299
300 if (bytes < 0)
301 return (-1);
302
303 fp->ptr = fp->buf;
304 }
305
306 return (0);
307 }
308
309
310 /*
311 * 'cupsFileGetChar()' - Get a single character from a file.
312 */
313
314 int /* O - Character or -1 on EOF */
315 cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
316 {
317 /*
318 * Range check input...
319 */
320
321 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
322 return (-1);
323
324 /*
325 * If the input buffer is empty, try to read more data...
326 */
327
328 if (fp->ptr >= fp->end)
329 if (cups_fill(fp) < 0)
330 return (-1);
331
332 /*
333 * Return the next character in the buffer...
334 */
335
336 return (*(fp->ptr)++ & 255);
337 }
338
339
340 /*
341 * 'cupsFileGetConf()' - Get a line from a configuration file...
342 */
343
344 char * /* O - Line read of NULL on eof/error */
345 cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
346 char *buf, /* O - String buffer */
347 size_t buflen, /* I - Size of string buffer */
348 char **value, /* O - Pointer to value */
349 int *linenum) /* IO - Current line number */
350 {
351 char *ptr; /* Pointer into line */
352
353
354 /*
355 * Range check input...
356 */
357
358 if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
359 !buf || buflen < 2 || !value)
360 {
361 if (value)
362 *value = NULL;
363
364 return (NULL);
365 }
366
367 /*
368 * Read the next non-comment line...
369 */
370
371 *value = NULL;
372
373 while (cupsFileGets(fp, buf, buflen))
374 {
375 (*linenum) ++;
376
377 /*
378 * Strip any comments...
379 */
380
381 if ((ptr = strchr(buf, '#')) != NULL)
382 {
383 while (ptr > buf)
384 {
385 if (!isspace(ptr[-1] & 255))
386 break;
387
388 ptr --;
389 }
390
391 *ptr = '\0';
392 }
393
394 /*
395 * Strip leading whitespace...
396 */
397
398 for (ptr = buf; isspace(*ptr & 255); ptr ++);
399
400 if (ptr > buf)
401 _cups_strcpy(buf, ptr);
402
403 /*
404 * See if there is anything left...
405 */
406
407 if (buf[0])
408 {
409 /*
410 * Yes, grab any value and return...
411 */
412
413 for (ptr = buf; *ptr; ptr ++)
414 if (isspace(*ptr & 255))
415 break;
416
417 if (*ptr)
418 {
419 /*
420 * Have a value, skip any other spaces...
421 */
422
423 while (isspace(*ptr & 255))
424 *ptr++ = '\0';
425
426 if (*ptr)
427 *value = ptr;
428
429 /*
430 * Strip trailing whitespace and > for lines that begin with <...
431 */
432
433 ptr += strlen(ptr) - 1;
434
435 if (buf[0] == '<' && *ptr == '>')
436 *ptr-- = '\0';
437 else if (buf[0] == '<' && *ptr != '>')
438 {
439 /*
440 * Syntax error...
441 */
442
443 *value = NULL;
444 return (buf);
445 }
446
447 while (ptr > *value && isspace(*ptr & 255))
448 *ptr-- = '\0';
449 }
450
451 /*
452 * Return the line...
453 */
454
455 return (buf);
456 }
457 }
458
459 return (NULL);
460 }
461
462
463 /*
464 * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
465 */
466
467 char * /* O - Line read or NULL on eof/error */
468 cupsFileGets(cups_file_t *fp, /* I - CUPS file */
469 char *buf, /* O - String buffer */
470 size_t buflen) /* I - Size of string buffer */
471 {
472 int ch; /* Character from file */
473 char *ptr, /* Current position in line buffer */
474 *end; /* End of line buffer */
475
476
477 /*
478 * Range check input...
479 */
480
481 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
482 return (NULL);
483
484 /*
485 * Now loop until we have a valid line...
486 */
487
488 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
489 {
490 if (fp->ptr >= fp->end)
491 if (cups_fill(fp) <= 0)
492 {
493 if (ptr == buf)
494 return (NULL);
495 else
496 break;
497 }
498
499 ch = *(fp->ptr)++;
500
501 if (ch == '\r')
502 {
503 /*
504 * Check for CR LF...
505 */
506
507 if (fp->ptr >= fp->end)
508 if (cups_fill(fp) <= 0)
509 break;
510
511 if (*(fp->ptr) == '\n')
512 fp->ptr ++;
513
514 break;
515 }
516 else if (ch == '\n')
517 {
518 /*
519 * Line feed ends a line...
520 */
521
522 break;
523 }
524 else
525 *ptr++ = ch;
526 }
527
528 *ptr = '\0';
529
530 return (buf);
531 }
532
533
534 /*
535 * 'cupsFileLock()' - Temporarily lock access to a file.
536 */
537
538 int /* O - 0 on success, -1 on error */
539 cupsFileLock(cups_file_t *fp, /* I - File to lock */
540 int block) /* I - 1 to wait for the lock, 0 to fail right away */
541 {
542 /*
543 * Range check...
544 */
545
546 if (!fp || fp->mode == 's')
547 return (-1);
548
549 /*
550 * Try the lock...
551 */
552
553 return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
554 }
555
556
557 /*
558 * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
559 */
560
561 int /* O - File descriptor */
562 cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
563 {
564 return (fp->fd);
565 }
566
567
568 /*
569 * 'cupsFileOpen()' - Open a CUPS file.
570 */
571
572 cups_file_t * /* O - CUPS file or NULL */
573 cupsFileOpen(const char *filename, /* I - Name of file */
574 const char *mode) /* I - Open mode */
575 {
576 cups_file_t *fp; /* New CUPS file */
577 int fd; /* File descriptor */
578 char hostname[1024], /* Hostname */
579 *portname; /* Port "name" (number or service) */
580 int port; /* Port number */
581 struct servent *service; /* Service */
582 int i; /* Looping var */
583 int val; /* Socket value */
584 struct hostent *hostaddr; /* Host address data */
585 http_addr_t sockaddr; /* Socket address */
586
587
588 /*
589 * Range check input...
590 */
591
592 if (!filename || !mode ||
593 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
594 return (NULL);
595
596 /*
597 * Open the file...
598 */
599
600 switch (*mode)
601 {
602 case 'a' : /* Append file */
603 fd = open(filename, O_RDWR | O_CREAT | O_APPEND, 0666);
604 break;
605
606 case 'r' : /* Read file */
607 fd = open(filename, O_RDONLY, 0);
608 break;
609
610 case 'w' : /* Write file */
611 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT, 0666);
612 break;
613
614 case 's' : /* Read/write socket */
615 strlcpy(hostname, filename, sizeof(hostname));
616 if ((portname = strrchr(hostname, ':')) != NULL)
617 *portname++ = '\0';
618 else
619 return (NULL);
620
621 if ((hostaddr = httpGetHostByName(hostname)) == NULL)
622 return (NULL);
623
624 if (isdigit(portname[0] & 255))
625 port = atoi(portname);
626 else if ((service = getservbyname(portname, NULL)) != NULL)
627 port = ntohs(service->s_port);
628 else
629 return (NULL);
630
631 for (i = 0, fd = -1; hostaddr->h_addr_list[i]; i ++)
632 {
633 /*
634 * Load the address...
635 */
636
637 httpAddrLoad(hostaddr, port, i, &sockaddr);
638
639 /*
640 * Create a socket...
641 */
642
643 if ((fd = socket(sockaddr.addr.sa_family, SOCK_STREAM, 0)) < 0)
644 continue;
645
646 val = 1;
647 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
648
649 #ifdef SO_REUSEPORT
650 val = 1;
651 setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &val, sizeof(val));
652 #endif /* SO_REUSEPORT */
653
654 /*
655 * Using TCP_NODELAY improves responsiveness, especially on systems
656 * with a slow loopback interface... Since we write large buffers
657 * when sending print files and requests, there shouldn't be any
658 * performance penalty for this...
659 */
660
661 val = 1;
662 setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val));
663
664 /*
665 * Connect to the server...
666 */
667
668 #ifdef AF_INET6
669 if (sockaddr.addr.sa_family == AF_INET6)
670 {
671 if (connect(fd, (struct sockaddr *)&sockaddr,
672 sizeof(sockaddr.ipv6)) < 0)
673 {
674 fd = -1;
675 continue;
676 }
677 }
678 else
679 #endif /* AF_INET6 */
680 if (connect(fd, (struct sockaddr *)&sockaddr,
681 sizeof(sockaddr.ipv4)) < 0)
682 {
683 fd = -1;
684 continue;
685 }
686 }
687 break;
688
689 default : /* Remove bogus compiler warning... */
690 return (NULL);
691 }
692
693 if (fd < 0)
694 return (NULL);
695
696 /*
697 * Create the CUPS file structure...
698 */
699
700 if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
701 {
702 if (*mode == 's')
703 closesocket(fd);
704 else
705 close(fd);
706 }
707
708 /*
709 * Return it...
710 */
711
712 return (fp);
713 }
714
715 /*
716 * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
717 */
718
719 cups_file_t * /* O - CUPS file or NULL */
720 cupsFileOpenFd(int fd, /* I - File descriptor */
721 const char *mode) /* I - Open mode */
722 {
723 cups_file_t *fp; /* New CUPS file */
724
725
726 /*
727 * Range check input...
728 */
729
730 if (fd < 0 || !mode ||
731 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
732 return (NULL);
733
734 /*
735 * Allocate memory...
736 */
737
738 if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
739 return (NULL);
740
741 /*
742 * Open the file...
743 */
744
745 fp->fd = fd;
746
747 switch (*mode)
748 {
749 case 'w' :
750 case 'a' :
751 fp->mode = 'w';
752 fp->ptr = fp->buf;
753 fp->end = fp->buf + sizeof(fp->buf);
754
755 #ifdef HAVE_LIBZ
756 if (mode[1] >= '1' && mode[1] <= '9')
757 {
758 /*
759 * Open a compressed stream, so write the standard gzip file
760 * header...
761 */
762
763 unsigned char header[10]; /* gzip file header */
764 time_t curtime; /* Current time */
765
766
767 curtime = time(NULL);
768 header[0] = 0x1f;
769 header[1] = 0x8b;
770 header[2] = Z_DEFLATED;
771 header[3] = 0;
772 header[4] = curtime;
773 header[5] = curtime >> 8;
774 header[6] = curtime >> 16;
775 header[7] = curtime >> 24;
776 header[8] = 0;
777 header[9] = 0x03;
778
779 cups_write(fp, (char *)header, 10);
780
781 /*
782 * Initialize the compressor...
783 */
784
785 deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
786 Z_DEFAULT_STRATEGY);
787
788 fp->stream.next_out = fp->cbuf;
789 fp->stream.avail_out = sizeof(fp->cbuf);
790 fp->compressed = 1;
791 fp->crc = crc32(0L, Z_NULL, 0);
792 }
793 #endif /* HAVE_LIBZ */
794 break;
795
796 case 'r' :
797 fp->mode = 'r';
798 break;
799
800 case 's' :
801 fp->mode = 's';
802 break;
803
804 default : /* Remove bogus compiler warning... */
805 return (NULL);
806 }
807
808 /*
809 * Don't pass this file to child processes...
810 */
811
812 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
813
814 return (fp);
815 }
816
817
818 /*
819 * 'cupsFilePeekChar()' - Peek at the next character from a file.
820 */
821
822 int /* O - Character or -1 on EOF */
823 cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
824 {
825 /*
826 * Range check input...
827 */
828
829 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
830 return (-1);
831
832 /*
833 * If the input buffer is empty, try to read more data...
834 */
835
836 if (fp->ptr >= fp->end)
837 if (cups_fill(fp) < 0)
838 return (-1);
839
840 /*
841 * Return the next character in the buffer...
842 */
843
844 return (*(fp->ptr) & 255);
845 }
846
847
848 /*
849 * 'cupsFilePrintf()' - Write a formatted string.
850 */
851
852 int /* O - Number of bytes written or -1 */
853 cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
854 const char *format, /* I - Printf-style format string */
855 ...) /* I - Additional args as necessary */
856 {
857 va_list ap; /* Argument list */
858 size_t bytes; /* Formatted size */
859 char buf[2048]; /* Formatted text */
860
861
862 if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
863 return (-1);
864
865 va_start(ap, format);
866 bytes = vsnprintf(buf, sizeof(buf), format, ap);
867 va_end(ap);
868
869 if (fp->mode == 's')
870 return (cups_write(fp, buf, bytes));
871
872 if ((fp->ptr + bytes) > fp->end)
873 if (cupsFileFlush(fp))
874 return (-1);
875
876 fp->pos += bytes;
877
878 if (bytes > sizeof(fp->buf))
879 {
880 if (fp->compressed)
881 return (cups_compress(fp, buf, bytes));
882 else
883 return (cups_write(fp, buf, bytes));
884 }
885 else
886 {
887 memcpy(fp->ptr, buf, bytes);
888 fp->ptr += bytes;
889 return (bytes);
890 }
891 }
892
893
894 /*
895 * 'cupsFilePutChar()' - Write a character.
896 */
897
898 int /* O - 0 on success, -1 on error */
899 cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
900 int c) /* I - Character to write */
901 {
902 /*
903 * Range check input...
904 */
905
906 if (!fp || (fp->mode != 'w' && fp->mode != 's'))
907 return (-1);
908
909 if (fp->mode == 's')
910 {
911 /*
912 * Send character immediately over socket...
913 */
914
915 char ch; /* Output character */
916
917
918 ch = c;
919
920 if (send(fp->fd, &ch, 1, 0) < 1)
921 return (-1);
922 }
923 else
924 {
925 /*
926 * Buffer it up...
927 */
928
929 if (fp->ptr >= fp->end)
930 if (cupsFileFlush(fp))
931 return (-1);
932
933 *(fp->ptr) ++ = c;
934 }
935
936 fp->pos ++;
937
938 return (0);
939 }
940
941
942 /*
943 * 'cupsFilePuts()' - Write a string.
944 */
945
946 int /* O - Number of bytes written or -1 */
947 cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
948 const char *s) /* I - String to write */
949 {
950 size_t bytes; /* Bytes to write */
951
952
953 /*
954 * Range check input...
955 */
956
957 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
958 return (-1);
959
960 /*
961 * Write the string...
962 */
963
964 bytes = strlen(s);
965
966 if (fp->mode == 's')
967 {
968 if (cups_write(fp, s, bytes) < 0)
969 return (-1);
970
971 fp->pos += bytes;
972
973 return (bytes);
974 }
975
976 if ((fp->ptr + bytes) > fp->end)
977 if (cupsFileFlush(fp))
978 return (-1);
979
980 fp->pos += bytes;
981
982 if (bytes > sizeof(fp->buf))
983 {
984 if (fp->compressed)
985 return (cups_compress(fp, s, bytes));
986 else
987 return (cups_write(fp, s, bytes));
988 }
989 else
990 {
991 memcpy(fp->ptr, s, bytes);
992 fp->ptr += bytes;
993 return (bytes);
994 }
995 }
996
997
998 /*
999 * 'cupsFileRead()' - Read from a file.
1000 */
1001
1002 ssize_t /* O - Number of bytes read or -1 */
1003 cupsFileRead(cups_file_t *fp, /* I - CUPS file */
1004 char *buf, /* O - Buffer */
1005 size_t bytes) /* I - Number of bytes to read */
1006 {
1007 size_t total, /* Total bytes read */
1008 count; /* Bytes read */
1009
1010
1011 DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1012 (long)bytes));
1013
1014 /*
1015 * Range check input...
1016 */
1017
1018 if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
1019 return (-1);
1020
1021 if (bytes == 0)
1022 return (0);
1023
1024 /*
1025 * Loop until all bytes are read...
1026 */
1027
1028 total = 0;
1029 while (bytes > 0)
1030 {
1031 if (fp->ptr >= fp->end)
1032 if (cups_fill(fp) <= 0)
1033 {
1034 DEBUG_printf((" cups_fill() returned -1, total=%d\n", total));
1035
1036 if (total > 0)
1037 return (total);
1038 else
1039 return (-1);
1040 }
1041
1042 count = fp->end - fp->ptr;
1043 if (count > bytes)
1044 count = bytes;
1045
1046 memcpy(buf, fp->ptr, count);
1047 fp->ptr += count;
1048
1049 /*
1050 * Update the counts for the last read...
1051 */
1052
1053 bytes -= count;
1054 total += count;
1055 buf += count;
1056 }
1057
1058 /*
1059 * Return the total number of bytes read...
1060 */
1061
1062 DEBUG_printf((" total=%d\n", total));
1063
1064 return (total);
1065 }
1066
1067
1068 /*
1069 * 'cupsFileRewind()' - Rewind a file.
1070 */
1071
1072 off_t /* O - New file position or -1 */
1073 cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
1074 {
1075 return (cupsFileSeek(fp, 0L));
1076 }
1077
1078
1079 /*
1080 * 'cupsFileSeek()' - Seek in a file.
1081 */
1082
1083 off_t /* O - New file position or -1 */
1084 cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
1085 off_t pos) /* I - Position in file */
1086 {
1087 size_t bytes; /* Number bytes in buffer */
1088
1089
1090 DEBUG_printf(("cupsFileSeek(fp=%p, pos=%ld)\n", fp, (long)pos));
1091 DEBUG_printf((" fp->pos=%ld\n", (long)fp->pos));
1092
1093 /*
1094 * Range check input...
1095 */
1096
1097 if (!fp || pos < 0 || fp->mode != 'r')
1098 return (-1);
1099
1100 /*
1101 * Figure out the number of bytes in the current buffer, and then
1102 * see if we are outside of it...
1103 */
1104
1105 bytes = fp->end - fp->buf;
1106 fp->eof = 0;
1107
1108 if (pos < fp->pos)
1109 {
1110 /*
1111 * Need to seek backwards...
1112 */
1113
1114 #ifdef HAVE_LIBZ
1115 if (fp->compressed)
1116 {
1117 inflateEnd(&fp->stream);
1118
1119 lseek(fp->fd, 0, SEEK_SET);
1120 fp->pos = 0;
1121 fp->ptr = NULL;
1122 fp->end = NULL;
1123
1124 while ((bytes = cups_fill(fp)) > 0)
1125 if (pos >= fp->pos && pos < (fp->pos + bytes))
1126 break;
1127
1128 if (bytes <= 0)
1129 return (-1);
1130 }
1131 else
1132 #endif /* HAVE_LIBZ */
1133 {
1134 fp->pos = lseek(fp->fd, pos, SEEK_SET);
1135 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
1136 fp->ptr = NULL;
1137 fp->end = NULL;
1138 }
1139 }
1140 else if (pos >= (fp->pos + bytes))
1141 {
1142 /*
1143 * Need to seek forwards...
1144 */
1145
1146 #ifdef HAVE_LIBZ
1147 if (fp->compressed)
1148 {
1149 while ((bytes = cups_fill(fp)) > 0)
1150 if (pos >= fp->pos && pos < (fp->pos + bytes))
1151 break;
1152
1153 if (bytes <= 0)
1154 return (-1);
1155 }
1156 else
1157 #endif /* HAVE_LIBZ */
1158 {
1159 fp->pos = lseek(fp->fd, pos, SEEK_SET);
1160 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
1161 fp->ptr = NULL;
1162 fp->end = NULL;
1163 }
1164 }
1165 else
1166 {
1167 /*
1168 * Just reposition the current pointer, since we have the right
1169 * range...
1170 */
1171
1172 fp->ptr = fp->buf + pos - fp->pos;
1173 DEBUG_puts((" seek inside buffer..."));
1174 }
1175
1176 return (fp->pos);
1177 }
1178
1179
1180 /*
1181 * 'cupsFileTell()' - Return the current file position.
1182 */
1183
1184 off_t /* O - File position */
1185 cupsFileTell(cups_file_t *fp) /* I - CUPS file */
1186 {
1187 return (fp->pos);
1188 }
1189
1190
1191 /*
1192 * 'cupsFileUnlock()' - Unlock access to a file.
1193 */
1194
1195 int /* O - 0 on success, -1 on error */
1196 cupsFileUnlock(cups_file_t *fp) /* I - File to lock */
1197 {
1198 /*
1199 * Range check...
1200 */
1201
1202 if (!fp || fp->mode == 's')
1203 return (-1);
1204
1205 /*
1206 * Unlock...
1207 */
1208
1209 return (lockf(fp->fd, F_ULOCK, 0));
1210 }
1211
1212
1213 /*
1214 * 'cupsFileWrite()' - Write to a file.
1215 */
1216
1217 ssize_t /* O - Number of bytes written */
1218 cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
1219 const char *buf, /* I - Buffer */
1220 size_t bytes) /* I - Number of bytes to write */
1221 {
1222 /*
1223 * Range check input...
1224 */
1225
1226 if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
1227 return (-1);
1228
1229 if (bytes == 0)
1230 return (0);
1231
1232 /*
1233 * Write the buffer...
1234 */
1235
1236 if (fp->mode == 's')
1237 {
1238 if (cups_write(fp, buf, bytes) < 0)
1239 return (-1);
1240
1241 fp->pos += bytes;
1242
1243 return (bytes);
1244 }
1245
1246 if ((fp->ptr + bytes) > fp->end)
1247 if (cupsFileFlush(fp))
1248 return (-1);
1249
1250 fp->pos += bytes;
1251
1252 if (bytes > sizeof(fp->buf))
1253 {
1254 if (fp->compressed)
1255 return (cups_compress(fp, buf, bytes));
1256 else
1257 return (cups_write(fp, buf, bytes));
1258 }
1259 else
1260 {
1261 memcpy(fp->ptr, buf, bytes);
1262 fp->ptr += bytes;
1263 return (bytes);
1264 }
1265 }
1266
1267
1268 #ifdef HAVE_LIBZ
1269 /*
1270 * 'cups_compress()' - Compress a buffer of data...
1271 */
1272
1273 static ssize_t /* O - Number of bytes written or -1 */
1274 cups_compress(cups_file_t *fp, /* I - CUPS file */
1275 const char *buf, /* I - Buffer */
1276 size_t bytes) /* I - Number bytes */
1277 {
1278 /*
1279 * Update the CRC...
1280 */
1281
1282 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
1283
1284 /*
1285 * Deflate the bytes...
1286 */
1287
1288 fp->stream.next_in = (Bytef *)buf;
1289 fp->stream.avail_in = bytes;
1290
1291 while (fp->stream.avail_in > 0)
1292 {
1293 /*
1294 * Flush the current buffer...
1295 */
1296
1297 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
1298 {
1299 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
1300 return (-1);
1301 }
1302
1303 deflate(&(fp->stream), Z_NO_FLUSH);
1304 }
1305
1306 return (bytes);
1307 }
1308 #endif /* HAVE_LIBZ */
1309
1310
1311 /*
1312 * 'cups_fill()' - Fill the input buffer...
1313 */
1314
1315 static ssize_t /* O - Number of bytes or -1 */
1316 cups_fill(cups_file_t *fp) /* I - CUPS file */
1317 {
1318 ssize_t bytes; /* Number of bytes read */
1319 #ifdef HAVE_LIBZ
1320 const unsigned char *ptr, /* Pointer into buffer */
1321 *end; /* End of buffer */
1322 #endif /* HAVE_LIBZ */
1323
1324
1325 DEBUG_printf(("cups_fill(fp=%p)\n", fp));
1326 DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->pos=%ld\n",
1327 fp->ptr, fp->end, fp->buf, (long)fp->pos));
1328
1329 /*
1330 * Update the "pos" element as needed...
1331 */
1332
1333 if (fp->ptr && fp->end)
1334 fp->pos += fp->end - fp->buf;
1335
1336 #ifdef HAVE_LIBZ
1337 while (!fp->ptr || fp->compressed)
1338 {
1339 /*
1340 * Check to see if we have read any data yet; if not, see if we have a
1341 * compressed file...
1342 */
1343
1344 if (!fp->ptr)
1345 {
1346 /*
1347 * Reset the file position in case we are seeking...
1348 */
1349
1350 fp->compressed = 0;
1351 fp->pos = 0;
1352
1353 /*
1354 * Read the first bytes in the file to determine if we have a gzip'd
1355 * file...
1356 */
1357
1358 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) < 0)
1359 {
1360 /*
1361 * Can't read from file!
1362 */
1363
1364 return (-1);
1365 }
1366
1367 if (bytes < 10 || fp->cbuf[0] != 0x1f || fp->cbuf[1] != 0x8b ||
1368 fp->cbuf[2] != 8 || (fp->cbuf[3] & 0xe0) != 0)
1369 {
1370 /*
1371 * Not a gzip'd file!
1372 */
1373
1374 memcpy(fp->buf, fp->cbuf, bytes);
1375
1376 fp->ptr = fp->buf;
1377 fp->end = fp->buf + bytes;
1378
1379 return (bytes);
1380 }
1381
1382 /*
1383 * Parse header junk: extra data, original name, and comment...
1384 */
1385
1386 ptr = (unsigned char *)fp->cbuf + 10;
1387 end = (unsigned char *)fp->cbuf + bytes;
1388
1389 if (fp->cbuf[3] & 0x04)
1390 {
1391 /*
1392 * Skip extra data...
1393 */
1394
1395 if ((ptr + 2) > end)
1396 {
1397 /*
1398 * Can't read from file!
1399 */
1400
1401 return (-1);
1402 }
1403
1404 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1405 ptr += 2 + bytes;
1406
1407 if (ptr > end)
1408 {
1409 /*
1410 * Can't read from file!
1411 */
1412
1413 return (-1);
1414 }
1415 }
1416
1417 if (fp->cbuf[3] & 0x08)
1418 {
1419 /*
1420 * Skip original name data...
1421 */
1422
1423 while (ptr < end && *ptr)
1424 ptr ++;
1425
1426 if (ptr < end)
1427 ptr ++;
1428 else
1429 {
1430 /*
1431 * Can't read from file!
1432 */
1433
1434 return (-1);
1435 }
1436 }
1437
1438 if (fp->cbuf[3] & 0x10)
1439 {
1440 /*
1441 * Skip comment data...
1442 */
1443
1444 while (ptr < end && *ptr)
1445 ptr ++;
1446
1447 if (ptr < end)
1448 ptr ++;
1449 else
1450 {
1451 /*
1452 * Can't read from file!
1453 */
1454
1455 return (-1);
1456 }
1457 }
1458
1459 if (fp->cbuf[3] & 0x02)
1460 {
1461 /*
1462 * Skip header CRC data...
1463 */
1464
1465 ptr += 2;
1466
1467 if (ptr > end)
1468 {
1469 /*
1470 * Can't read from file!
1471 */
1472
1473 return (-1);
1474 }
1475 }
1476
1477 /*
1478 * Setup the decompressor data...
1479 */
1480
1481 fp->stream.zalloc = (alloc_func)0;
1482 fp->stream.zfree = (free_func)0;
1483 fp->stream.opaque = (voidpf)0;
1484 fp->stream.next_in = (Bytef *)ptr;
1485 fp->stream.next_out = NULL;
1486 fp->stream.avail_in = end - ptr;
1487 fp->stream.avail_out = 0;
1488 fp->crc = crc32(0L, Z_NULL, 0);
1489
1490 if (inflateInit2(&(fp->stream), -15) != Z_OK)
1491 return (-1);
1492
1493 fp->compressed = 1;
1494 }
1495
1496 if (fp->compressed)
1497 {
1498 /*
1499 * If we have reached end-of-file, return immediately...
1500 */
1501
1502 if (fp->eof)
1503 return (-1);
1504
1505 /*
1506 * Fill the decompression buffer as needed...
1507 */
1508
1509 if (fp->stream.avail_in == 0)
1510 {
1511 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1512 return (-1);
1513
1514 fp->stream.next_in = fp->cbuf;
1515 fp->stream.avail_in = bytes;
1516 }
1517
1518 /*
1519 * Decompress data from the buffer...
1520 */
1521
1522 fp->stream.next_out = (Bytef *)fp->buf;
1523 fp->stream.avail_out = sizeof(fp->buf);
1524
1525 if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
1526 {
1527 /*
1528 * Read the CRC and length...
1529 */
1530
1531 unsigned char trailer[8]; /* Trailer bytes */
1532 uLong tcrc; /* Trailer CRC */
1533
1534
1535 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
1536 {
1537 /*
1538 * Can't get it, so mark end-of-file...
1539 */
1540
1541 fp->eof = 1;
1542 return (-1);
1543 }
1544
1545 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
1546 trailer[0];
1547
1548 if (tcrc != fp->crc)
1549 {
1550 /*
1551 * Bad CRC, mark end-of-file...
1552 */
1553 fp->eof = 1;
1554
1555 return (-1);
1556 }
1557
1558 /*
1559 * Otherwise, reset the current pointer so that we re-read the
1560 * file header...
1561 */
1562
1563 fp->ptr = NULL;
1564 continue;
1565 }
1566
1567 bytes = sizeof(fp->buf) - fp->stream.avail_out;
1568
1569 /*
1570 * Return the decompressed data...
1571 */
1572
1573 fp->ptr = fp->buf;
1574 fp->end = fp->buf + bytes;
1575
1576 return (bytes);
1577 }
1578 }
1579 #endif /* HAVE_LIBZ */
1580
1581 /*
1582 * Read a buffer's full of data...
1583 */
1584
1585 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1586 {
1587 /*
1588 * Can't read from file!
1589 */
1590
1591 fp->eof = 1;
1592 fp->ptr = fp->buf;
1593 fp->end = fp->buf;
1594
1595 return (-1);
1596 }
1597
1598 /*
1599 * Return the bytes we read...
1600 */
1601
1602 fp->eof = 0;
1603 fp->ptr = fp->buf;
1604 fp->end = fp->buf + bytes;
1605
1606 return (bytes);
1607 }
1608
1609
1610 /*
1611 * 'cups_read()' - Read from a file descriptor.
1612 */
1613
1614 static ssize_t /* O - Number of bytes read or -1 */
1615 cups_read(cups_file_t *fp, /* I - CUPS file */
1616 char *buf, /* I - Buffer */
1617 size_t bytes) /* I - Number bytes */
1618 {
1619 ssize_t total; /* Total bytes read */
1620
1621
1622 /*
1623 * Loop until we read at least 0 bytes...
1624 */
1625
1626 for (;;)
1627 {
1628 if (fp->mode == 's')
1629 total = recv(fp->fd, buf, bytes, 0);
1630 else
1631 total = read(fp->fd, buf, bytes);
1632
1633 if (total >= 0)
1634 break;
1635
1636 /*
1637 * Reads can be interrupted by signals and unavailable resources...
1638 */
1639
1640 if (errno == EAGAIN || errno == EINTR)
1641 continue;
1642 else
1643 return (-1);
1644 }
1645
1646 /*
1647 * Return the total number of bytes read...
1648 */
1649
1650 return (total);
1651 }
1652
1653
1654 /*
1655 * 'cups_write()' - Write to a file descriptor.
1656 */
1657
1658 static ssize_t /* O - Number of bytes written or -1 */
1659 cups_write(cups_file_t *fp, /* I - CUPS file */
1660 const char *buf, /* I - Buffer */
1661 size_t bytes) /* I - Number bytes */
1662 {
1663 size_t total, /* Total bytes written */
1664 count; /* Count this time */
1665
1666
1667 /*
1668 * Loop until all bytes are written...
1669 */
1670
1671 total = 0;
1672 while (bytes > 0)
1673 {
1674 if (fp->mode == 's')
1675 count = send(fp->fd, buf, bytes, 0);
1676 else
1677 count = write(fp->fd, buf, bytes);
1678
1679 if (count < 0)
1680 {
1681 /*
1682 * Writes can be interrupted by signals and unavailable resources...
1683 */
1684
1685 if (errno == EAGAIN || errno == EINTR)
1686 continue;
1687 else
1688 return (-1);
1689 }
1690
1691 /*
1692 * Update the counts for the last write call...
1693 */
1694
1695 bytes -= count;
1696 total += count;
1697 buf += count;
1698 }
1699
1700 /*
1701 * Return the total number of bytes written...
1702 */
1703
1704 return (total);
1705 }
1706
1707
1708 /*
1709 * End of "$Id$".
1710 */