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