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