]> 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 5057 2006-02-02 20:38:29Z 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 * 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 if (bytes > 0)
390 {
391 #ifdef HAVE_LIBZ
392 if (fp->compressed)
393 bytes = cups_compress(fp, fp->buf, bytes);
394 else
395 #endif /* HAVE_LIBZ */
396 bytes = cups_write(fp, fp->buf, bytes);
397
398 if (bytes < 0)
399 return (-1);
400
401 fp->ptr = fp->buf;
402 }
403
404 return (0);
405 }
406
407
408 /*
409 * 'cupsFileGetChar()' - Get a single character from a file.
410 */
411
412 int /* O - Character or -1 on EOF */
413 cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
414 {
415 /*
416 * Range check input...
417 */
418
419 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
420 return (-1);
421
422 /*
423 * If the input buffer is empty, try to read more data...
424 */
425
426 if (fp->ptr >= fp->end)
427 if (cups_fill(fp) < 0)
428 return (-1);
429
430 /*
431 * Return the next character in the buffer...
432 */
433
434 return (*(fp->ptr)++ & 255);
435 }
436
437
438 /*
439 * 'cupsFileGetConf()' - Get a line from a configuration file...
440 */
441
442 char * /* O - Line read of NULL on eof/error */
443 cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
444 char *buf, /* O - String buffer */
445 size_t buflen, /* I - Size of string buffer */
446 char **value, /* O - Pointer to value */
447 int *linenum) /* IO - Current line number */
448 {
449 char *ptr; /* Pointer into line */
450
451
452 /*
453 * Range check input...
454 */
455
456 if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
457 !buf || buflen < 2 || !value)
458 {
459 if (value)
460 *value = NULL;
461
462 return (NULL);
463 }
464
465 /*
466 * Read the next non-comment line...
467 */
468
469 *value = NULL;
470
471 while (cupsFileGets(fp, buf, buflen))
472 {
473 (*linenum) ++;
474
475 /*
476 * Strip any comments...
477 */
478
479 if ((ptr = strchr(buf, '#')) != NULL)
480 {
481 while (ptr > buf)
482 {
483 if (!isspace(ptr[-1] & 255))
484 break;
485
486 ptr --;
487 }
488
489 *ptr = '\0';
490 }
491
492 /*
493 * Strip leading whitespace...
494 */
495
496 for (ptr = buf; isspace(*ptr & 255); ptr ++);
497
498 if (ptr > buf)
499 _cups_strcpy(buf, ptr);
500
501 /*
502 * See if there is anything left...
503 */
504
505 if (buf[0])
506 {
507 /*
508 * Yes, grab any value and return...
509 */
510
511 for (ptr = buf; *ptr; ptr ++)
512 if (isspace(*ptr & 255))
513 break;
514
515 if (*ptr)
516 {
517 /*
518 * Have a value, skip any other spaces...
519 */
520
521 while (isspace(*ptr & 255))
522 *ptr++ = '\0';
523
524 if (*ptr)
525 *value = ptr;
526
527 /*
528 * Strip trailing whitespace and > for lines that begin with <...
529 */
530
531 ptr += strlen(ptr) - 1;
532
533 if (buf[0] == '<' && *ptr == '>')
534 *ptr-- = '\0';
535 else if (buf[0] == '<' && *ptr != '>')
536 {
537 /*
538 * Syntax error...
539 */
540
541 *value = NULL;
542 return (buf);
543 }
544
545 while (ptr > *value && isspace(*ptr & 255))
546 *ptr-- = '\0';
547 }
548
549 /*
550 * Return the line...
551 */
552
553 return (buf);
554 }
555 }
556
557 return (NULL);
558 }
559
560
561 /*
562 * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
563 */
564
565 char * /* O - Line read or NULL on eof/error */
566 cupsFileGets(cups_file_t *fp, /* I - CUPS file */
567 char *buf, /* O - String buffer */
568 size_t buflen) /* I - Size of string buffer */
569 {
570 int ch; /* Character from file */
571 char *ptr, /* Current position in line buffer */
572 *end; /* End of line buffer */
573
574
575 /*
576 * Range check input...
577 */
578
579 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
580 return (NULL);
581
582 /*
583 * Now loop until we have a valid line...
584 */
585
586 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
587 {
588 if (fp->ptr >= fp->end)
589 if (cups_fill(fp) <= 0)
590 {
591 if (ptr == buf)
592 return (NULL);
593 else
594 break;
595 }
596
597 ch = *(fp->ptr)++;
598
599 if (ch == '\r')
600 {
601 /*
602 * Check for CR LF...
603 */
604
605 if (fp->ptr >= fp->end)
606 if (cups_fill(fp) <= 0)
607 break;
608
609 if (*(fp->ptr) == '\n')
610 fp->ptr ++;
611
612 break;
613 }
614 else if (ch == '\n')
615 {
616 /*
617 * Line feed ends a line...
618 */
619
620 break;
621 }
622 else
623 *ptr++ = ch;
624 }
625
626 *ptr = '\0';
627
628 return (buf);
629 }
630
631
632 /*
633 * 'cupsFileLock()' - Temporarily lock access to a file.
634 */
635
636 int /* O - 0 on success, -1 on error */
637 cupsFileLock(cups_file_t *fp, /* I - File to lock */
638 int block) /* I - 1 to wait for the lock, 0 to fail right away */
639 {
640 /*
641 * Range check...
642 */
643
644 if (!fp || fp->mode == 's')
645 return (-1);
646
647 /*
648 * Try the lock...
649 */
650
651 #ifdef WIN32
652 return (locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
653 #else
654 return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
655 #endif /* WIN32 */
656 }
657
658
659 /*
660 * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
661 */
662
663 int /* O - File descriptor */
664 cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
665 {
666 return (fp->fd);
667 }
668
669
670 /*
671 * 'cupsFileOpen()' - Open a CUPS file.
672 */
673
674 cups_file_t * /* O - CUPS file or NULL */
675 cupsFileOpen(const char *filename, /* I - Name of file */
676 const char *mode) /* I - Open mode */
677 {
678 cups_file_t *fp; /* New CUPS file */
679 int fd; /* File descriptor */
680 char hostname[1024], /* Hostname */
681 *portname; /* Port "name" (number or service) */
682 http_addrlist_t *addrlist; /* Host address list */
683
684
685 /*
686 * Range check input...
687 */
688
689 if (!filename || !mode ||
690 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
691 return (NULL);
692
693 /*
694 * Open the file...
695 */
696
697 switch (*mode)
698 {
699 case 'a' : /* Append file */
700 fd = open(filename, O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE, 0666);
701 break;
702
703 case 'r' : /* Read file */
704 fd = open(filename, O_RDONLY | O_LARGEFILE, 0);
705 break;
706
707 case 'w' : /* Write file */
708 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_LARGEFILE, 0666);
709 break;
710
711 case 's' : /* Read/write socket */
712 strlcpy(hostname, filename, sizeof(hostname));
713 if ((portname = strrchr(hostname, ':')) != NULL)
714 *portname++ = '\0';
715 else
716 return (NULL);
717
718 /*
719 * Lookup the hostname and service...
720 */
721
722 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
723 return (NULL);
724
725 /*
726 * Connect to the server...
727 */
728
729 if (!httpAddrConnect(addrlist, &fd))
730 {
731 httpAddrFreeList(addrlist);
732 return (NULL);
733 }
734
735 httpAddrFreeList(addrlist);
736 break;
737
738 default : /* Remove bogus compiler warning... */
739 return (NULL);
740 }
741
742 if (fd < 0)
743 return (NULL);
744
745 /*
746 * Create the CUPS file structure...
747 */
748
749 if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
750 {
751 if (*mode == 's')
752 closesocket(fd);
753 else
754 close(fd);
755 }
756
757 /*
758 * Return it...
759 */
760
761 return (fp);
762 }
763
764 /*
765 * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
766 */
767
768 cups_file_t * /* O - CUPS file or NULL */
769 cupsFileOpenFd(int fd, /* I - File descriptor */
770 const char *mode) /* I - Open mode */
771 {
772 cups_file_t *fp; /* New CUPS file */
773
774
775 /*
776 * Range check input...
777 */
778
779 if (fd < 0 || !mode ||
780 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's'))
781 return (NULL);
782
783 /*
784 * Allocate memory...
785 */
786
787 if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
788 return (NULL);
789
790 /*
791 * Open the file...
792 */
793
794 fp->fd = fd;
795
796 switch (*mode)
797 {
798 case 'w' :
799 case 'a' :
800 fp->mode = 'w';
801 fp->ptr = fp->buf;
802 fp->end = fp->buf + sizeof(fp->buf);
803
804 #ifdef HAVE_LIBZ
805 if (mode[1] >= '1' && mode[1] <= '9')
806 {
807 /*
808 * Open a compressed stream, so write the standard gzip file
809 * header...
810 */
811
812 unsigned char header[10]; /* gzip file header */
813 time_t curtime; /* Current time */
814
815
816 curtime = time(NULL);
817 header[0] = 0x1f;
818 header[1] = 0x8b;
819 header[2] = Z_DEFLATED;
820 header[3] = 0;
821 header[4] = curtime;
822 header[5] = curtime >> 8;
823 header[6] = curtime >> 16;
824 header[7] = curtime >> 24;
825 header[8] = 0;
826 header[9] = 0x03;
827
828 cups_write(fp, (char *)header, 10);
829
830 /*
831 * Initialize the compressor...
832 */
833
834 deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
835 Z_DEFAULT_STRATEGY);
836
837 fp->stream.next_out = fp->cbuf;
838 fp->stream.avail_out = sizeof(fp->cbuf);
839 fp->compressed = 1;
840 fp->crc = crc32(0L, Z_NULL, 0);
841 }
842 #endif /* HAVE_LIBZ */
843 break;
844
845 case 'r' :
846 fp->mode = 'r';
847 break;
848
849 case 's' :
850 fp->mode = 's';
851 break;
852
853 default : /* Remove bogus compiler warning... */
854 return (NULL);
855 }
856
857 /*
858 * Don't pass this file to child processes...
859 */
860
861 #ifndef WIN32
862 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
863 #endif /* !WIN32 */
864
865 return (fp);
866 }
867
868
869 /*
870 * 'cupsFilePeekChar()' - Peek at the next character from a file.
871 */
872
873 int /* O - Character or -1 on EOF */
874 cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
875 {
876 /*
877 * Range check input...
878 */
879
880 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
881 return (-1);
882
883 /*
884 * If the input buffer is empty, try to read more data...
885 */
886
887 if (fp->ptr >= fp->end)
888 if (cups_fill(fp) < 0)
889 return (-1);
890
891 /*
892 * Return the next character in the buffer...
893 */
894
895 return (*(fp->ptr) & 255);
896 }
897
898
899 /*
900 * 'cupsFilePrintf()' - Write a formatted string.
901 */
902
903 int /* O - Number of bytes written or -1 */
904 cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
905 const char *format, /* I - Printf-style format string */
906 ...) /* I - Additional args as necessary */
907 {
908 va_list ap; /* Argument list */
909 size_t bytes; /* Formatted size */
910 char buf[2048]; /* Formatted text */
911
912
913 if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
914 return (-1);
915
916 va_start(ap, format);
917 bytes = vsnprintf(buf, sizeof(buf), format, ap);
918 va_end(ap);
919
920 if (fp->mode == 's')
921 return (cups_write(fp, buf, bytes));
922
923 if ((fp->ptr + bytes) > fp->end)
924 if (cupsFileFlush(fp))
925 return (-1);
926
927 fp->pos += bytes;
928
929 if (bytes > sizeof(fp->buf))
930 {
931 #ifdef HAVE_LIBZ
932 if (fp->compressed)
933 return (cups_compress(fp, buf, bytes));
934 else
935 #endif /* HAVE_LIBZ */
936 return (cups_write(fp, buf, bytes));
937 }
938 else
939 {
940 memcpy(fp->ptr, buf, bytes);
941 fp->ptr += bytes;
942 return (bytes);
943 }
944 }
945
946
947 /*
948 * 'cupsFilePutChar()' - Write a character.
949 */
950
951 int /* O - 0 on success, -1 on error */
952 cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
953 int c) /* I - Character to write */
954 {
955 /*
956 * Range check input...
957 */
958
959 if (!fp || (fp->mode != 'w' && fp->mode != 's'))
960 return (-1);
961
962 if (fp->mode == 's')
963 {
964 /*
965 * Send character immediately over socket...
966 */
967
968 char ch; /* Output character */
969
970
971 ch = c;
972
973 if (send(fp->fd, &ch, 1, 0) < 1)
974 return (-1);
975 }
976 else
977 {
978 /*
979 * Buffer it up...
980 */
981
982 if (fp->ptr >= fp->end)
983 if (cupsFileFlush(fp))
984 return (-1);
985
986 *(fp->ptr) ++ = c;
987 }
988
989 fp->pos ++;
990
991 return (0);
992 }
993
994
995 /*
996 * 'cupsFilePuts()' - Write a string.
997 */
998
999 int /* O - Number of bytes written or -1 */
1000 cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
1001 const char *s) /* I - String to write */
1002 {
1003 size_t bytes; /* Bytes to write */
1004
1005
1006 /*
1007 * Range check input...
1008 */
1009
1010 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1011 return (-1);
1012
1013 /*
1014 * Write the string...
1015 */
1016
1017 bytes = strlen(s);
1018
1019 if (fp->mode == 's')
1020 {
1021 if (cups_write(fp, s, bytes) < 0)
1022 return (-1);
1023
1024 fp->pos += bytes;
1025
1026 return (bytes);
1027 }
1028
1029 if ((fp->ptr + bytes) > fp->end)
1030 if (cupsFileFlush(fp))
1031 return (-1);
1032
1033 fp->pos += bytes;
1034
1035 if (bytes > sizeof(fp->buf))
1036 {
1037 #ifdef HAVE_LIBZ
1038 if (fp->compressed)
1039 return (cups_compress(fp, s, bytes));
1040 else
1041 #endif /* HAVE_LIBZ */
1042 return (cups_write(fp, s, bytes));
1043 }
1044 else
1045 {
1046 memcpy(fp->ptr, s, bytes);
1047 fp->ptr += bytes;
1048 return (bytes);
1049 }
1050 }
1051
1052
1053 /*
1054 * 'cupsFileRead()' - Read from a file.
1055 */
1056
1057 ssize_t /* O - Number of bytes read or -1 */
1058 cupsFileRead(cups_file_t *fp, /* I - CUPS file */
1059 char *buf, /* O - Buffer */
1060 size_t bytes) /* I - Number of bytes to read */
1061 {
1062 size_t total, /* Total bytes read */
1063 count; /* Bytes read */
1064
1065
1066 DEBUG_printf(("cupsFileRead(fp=%p, buf=%p, bytes=%ld)\n", fp, buf,
1067 (long)bytes));
1068
1069 /*
1070 * Range check input...
1071 */
1072
1073 if (!fp || !buf || bytes < 0 || (fp->mode != 'r' && fp->mode != 's'))
1074 return (-1);
1075
1076 if (bytes == 0)
1077 return (0);
1078
1079 /*
1080 * Loop until all bytes are read...
1081 */
1082
1083 total = 0;
1084 while (bytes > 0)
1085 {
1086 if (fp->ptr >= fp->end)
1087 if (cups_fill(fp) <= 0)
1088 {
1089 DEBUG_printf((" cups_fill() returned -1, total=%d\n", total));
1090
1091 if (total > 0)
1092 return (total);
1093 else
1094 return (-1);
1095 }
1096
1097 count = fp->end - fp->ptr;
1098 if (count > bytes)
1099 count = bytes;
1100
1101 memcpy(buf, fp->ptr, count);
1102 fp->ptr += count;
1103
1104 /*
1105 * Update the counts for the last read...
1106 */
1107
1108 bytes -= count;
1109 total += count;
1110 buf += count;
1111 }
1112
1113 /*
1114 * Return the total number of bytes read...
1115 */
1116
1117 DEBUG_printf((" total=%d\n", total));
1118
1119 return (total);
1120 }
1121
1122
1123 /*
1124 * 'cupsFileRewind()' - Rewind a file.
1125 */
1126
1127 off_t /* O - New file position or -1 */
1128 cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
1129 {
1130 return (cupsFileSeek(fp, 0L));
1131 }
1132
1133
1134 /*
1135 * 'cupsFileSeek()' - Seek in a file.
1136 */
1137
1138 off_t /* O - New file position or -1 */
1139 cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
1140 off_t pos) /* I - Position in file */
1141 {
1142 size_t bytes; /* Number bytes in buffer */
1143
1144
1145 DEBUG_printf(("cupsFileSeek(fp=%p, pos=%ld)\n", fp, (long)pos));
1146 DEBUG_printf((" fp->pos=%ld\n", (long)fp->pos));
1147
1148 /*
1149 * Range check input...
1150 */
1151
1152 if (!fp || pos < 0 || fp->mode != 'r')
1153 return (-1);
1154
1155 /*
1156 * Figure out the number of bytes in the current buffer, and then
1157 * see if we are outside of it...
1158 */
1159
1160 bytes = fp->end - fp->buf;
1161 fp->eof = 0;
1162
1163 if (pos < fp->pos)
1164 {
1165 /*
1166 * Need to seek backwards...
1167 */
1168
1169 #ifdef HAVE_LIBZ
1170 if (fp->compressed)
1171 {
1172 inflateEnd(&fp->stream);
1173
1174 lseek(fp->fd, 0, SEEK_SET);
1175 fp->pos = 0;
1176 fp->ptr = NULL;
1177 fp->end = NULL;
1178
1179 while ((bytes = cups_fill(fp)) > 0)
1180 if (pos >= fp->pos && pos < (fp->pos + bytes))
1181 break;
1182
1183 if (bytes <= 0)
1184 return (-1);
1185 }
1186 else
1187 #endif /* HAVE_LIBZ */
1188 {
1189 fp->pos = lseek(fp->fd, pos, SEEK_SET);
1190 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
1191 fp->ptr = NULL;
1192 fp->end = NULL;
1193 }
1194 }
1195 else if (pos >= (fp->pos + bytes))
1196 {
1197 /*
1198 * Need to seek forwards...
1199 */
1200
1201 #ifdef HAVE_LIBZ
1202 if (fp->compressed)
1203 {
1204 while ((bytes = cups_fill(fp)) > 0)
1205 if (pos >= fp->pos && pos < (fp->pos + bytes))
1206 break;
1207
1208 if (bytes <= 0)
1209 return (-1);
1210 }
1211 else
1212 #endif /* HAVE_LIBZ */
1213 {
1214 fp->pos = lseek(fp->fd, pos, SEEK_SET);
1215 DEBUG_printf((" lseek() returned %ld...\n", (long)fp->pos));
1216 fp->ptr = NULL;
1217 fp->end = NULL;
1218 }
1219 }
1220 else
1221 {
1222 /*
1223 * Just reposition the current pointer, since we have the right
1224 * range...
1225 */
1226
1227 fp->ptr = fp->buf + pos - fp->pos;
1228 DEBUG_puts((" seek inside buffer..."));
1229 }
1230
1231 return (fp->pos);
1232 }
1233
1234
1235 /*
1236 * 'cupsFileTell()' - Return the current file position.
1237 */
1238
1239 off_t /* O - File position */
1240 cupsFileTell(cups_file_t *fp) /* I - CUPS file */
1241 {
1242 return (fp->pos);
1243 }
1244
1245
1246 /*
1247 * 'cupsFileUnlock()' - Unlock access to a file.
1248 */
1249
1250 int /* O - 0 on success, -1 on error */
1251 cupsFileUnlock(cups_file_t *fp) /* I - File to lock */
1252 {
1253 /*
1254 * Range check...
1255 */
1256
1257 if (!fp || fp->mode == 's')
1258 return (-1);
1259
1260 /*
1261 * Unlock...
1262 */
1263
1264 #ifdef WIN32
1265 return (locking(fp->fd, _LK_UNLCK, 0));
1266 #else
1267 return (lockf(fp->fd, F_ULOCK, 0));
1268 #endif /* WIN32 */
1269 }
1270
1271
1272 /*
1273 * 'cupsFileWrite()' - Write to a file.
1274 */
1275
1276 ssize_t /* O - Number of bytes written */
1277 cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
1278 const char *buf, /* I - Buffer */
1279 size_t bytes) /* I - Number of bytes to write */
1280 {
1281 /*
1282 * Range check input...
1283 */
1284
1285 if (!fp || !buf || bytes < 0 || (fp->mode != 'w' && fp->mode != 's'))
1286 return (-1);
1287
1288 if (bytes == 0)
1289 return (0);
1290
1291 /*
1292 * Write the buffer...
1293 */
1294
1295 if (fp->mode == 's')
1296 {
1297 if (cups_write(fp, buf, bytes) < 0)
1298 return (-1);
1299
1300 fp->pos += bytes;
1301
1302 return (bytes);
1303 }
1304
1305 if ((fp->ptr + bytes) > fp->end)
1306 if (cupsFileFlush(fp))
1307 return (-1);
1308
1309 fp->pos += bytes;
1310
1311 if (bytes > sizeof(fp->buf))
1312 {
1313 #ifdef HAVE_LIBZ
1314 if (fp->compressed)
1315 return (cups_compress(fp, buf, bytes));
1316 else
1317 #endif /* HAVE_LIBZ */
1318 return (cups_write(fp, buf, bytes));
1319 }
1320 else
1321 {
1322 memcpy(fp->ptr, buf, bytes);
1323 fp->ptr += bytes;
1324 return (bytes);
1325 }
1326 }
1327
1328
1329 #ifdef HAVE_LIBZ
1330 /*
1331 * 'cups_compress()' - Compress a buffer of data...
1332 */
1333
1334 static ssize_t /* O - Number of bytes written or -1 */
1335 cups_compress(cups_file_t *fp, /* I - CUPS file */
1336 const char *buf, /* I - Buffer */
1337 size_t bytes) /* I - Number bytes */
1338 {
1339 /*
1340 * Update the CRC...
1341 */
1342
1343 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
1344
1345 /*
1346 * Deflate the bytes...
1347 */
1348
1349 fp->stream.next_in = (Bytef *)buf;
1350 fp->stream.avail_in = bytes;
1351
1352 while (fp->stream.avail_in > 0)
1353 {
1354 /*
1355 * Flush the current buffer...
1356 */
1357
1358 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
1359 {
1360 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
1361 return (-1);
1362 }
1363
1364 deflate(&(fp->stream), Z_NO_FLUSH);
1365 }
1366
1367 return (bytes);
1368 }
1369 #endif /* HAVE_LIBZ */
1370
1371
1372 /*
1373 * 'cups_fill()' - Fill the input buffer...
1374 */
1375
1376 static ssize_t /* O - Number of bytes or -1 */
1377 cups_fill(cups_file_t *fp) /* I - CUPS file */
1378 {
1379 ssize_t bytes; /* Number of bytes read */
1380 #ifdef HAVE_LIBZ
1381 const unsigned char *ptr, /* Pointer into buffer */
1382 *end; /* End of buffer */
1383 #endif /* HAVE_LIBZ */
1384
1385
1386 DEBUG_printf(("cups_fill(fp=%p)\n", fp));
1387 DEBUG_printf((" fp->ptr=%p, fp->end=%p, fp->buf=%p, fp->pos=%ld\n",
1388 fp->ptr, fp->end, fp->buf, (long)fp->pos));
1389
1390 /*
1391 * Update the "pos" element as needed...
1392 */
1393
1394 if (fp->ptr && fp->end)
1395 fp->pos += fp->end - fp->buf;
1396
1397 #ifdef HAVE_LIBZ
1398 while (!fp->ptr || fp->compressed)
1399 {
1400 /*
1401 * Check to see if we have read any data yet; if not, see if we have a
1402 * compressed file...
1403 */
1404
1405 if (!fp->ptr)
1406 {
1407 /*
1408 * Reset the file position in case we are seeking...
1409 */
1410
1411 fp->compressed = 0;
1412 fp->pos = 0;
1413
1414 /*
1415 * Read the first bytes in the file to determine if we have a gzip'd
1416 * file...
1417 */
1418
1419 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
1420 {
1421 /*
1422 * Can't read from file!
1423 */
1424
1425 return (-1);
1426 }
1427
1428 if (bytes < 10 || fp->buf[0] != 0x1f ||
1429 (fp->buf[1] & 255) != 0x8b ||
1430 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
1431 {
1432 /*
1433 * Not a gzip'd file!
1434 */
1435
1436 fp->ptr = fp->buf;
1437 fp->end = fp->buf + bytes;
1438
1439 return (bytes);
1440 }
1441
1442 /*
1443 * Parse header junk: extra data, original name, and comment...
1444 */
1445
1446 ptr = (unsigned char *)fp->buf + 10;
1447 end = (unsigned char *)fp->buf + bytes;
1448
1449 if (fp->buf[3] & 0x04)
1450 {
1451 /*
1452 * Skip extra data...
1453 */
1454
1455 if ((ptr + 2) > end)
1456 {
1457 /*
1458 * Can't read from file!
1459 */
1460
1461 return (-1);
1462 }
1463
1464 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
1465 ptr += 2 + bytes;
1466
1467 if (ptr > end)
1468 {
1469 /*
1470 * Can't read from file!
1471 */
1472
1473 return (-1);
1474 }
1475 }
1476
1477 if (fp->buf[3] & 0x08)
1478 {
1479 /*
1480 * Skip original name data...
1481 */
1482
1483 while (ptr < end && *ptr)
1484 ptr ++;
1485
1486 if (ptr < end)
1487 ptr ++;
1488 else
1489 {
1490 /*
1491 * Can't read from file!
1492 */
1493
1494 return (-1);
1495 }
1496 }
1497
1498 if (fp->buf[3] & 0x10)
1499 {
1500 /*
1501 * Skip comment data...
1502 */
1503
1504 while (ptr < end && *ptr)
1505 ptr ++;
1506
1507 if (ptr < end)
1508 ptr ++;
1509 else
1510 {
1511 /*
1512 * Can't read from file!
1513 */
1514
1515 return (-1);
1516 }
1517 }
1518
1519 if (fp->buf[3] & 0x02)
1520 {
1521 /*
1522 * Skip header CRC data...
1523 */
1524
1525 ptr += 2;
1526
1527 if (ptr > end)
1528 {
1529 /*
1530 * Can't read from file!
1531 */
1532
1533 return (-1);
1534 }
1535 }
1536
1537 /*
1538 * Copy the flate-compressed data to the compression buffer...
1539 */
1540
1541 if ((bytes = end - ptr) > 0)
1542 memcpy(fp->cbuf, ptr, bytes);
1543
1544 /*
1545 * Setup the decompressor data...
1546 */
1547
1548 fp->stream.zalloc = (alloc_func)0;
1549 fp->stream.zfree = (free_func)0;
1550 fp->stream.opaque = (voidpf)0;
1551 fp->stream.next_in = (Bytef *)fp->cbuf;
1552 fp->stream.next_out = NULL;
1553 fp->stream.avail_in = bytes;
1554 fp->stream.avail_out = 0;
1555 fp->crc = crc32(0L, Z_NULL, 0);
1556
1557 if (inflateInit2(&(fp->stream), -15) != Z_OK)
1558 return (-1);
1559
1560 fp->compressed = 1;
1561 }
1562
1563 if (fp->compressed)
1564 {
1565 /*
1566 * If we have reached end-of-file, return immediately...
1567 */
1568
1569 if (fp->eof)
1570 return (-1);
1571
1572 /*
1573 * Fill the decompression buffer as needed...
1574 */
1575
1576 if (fp->stream.avail_in == 0)
1577 {
1578 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
1579 return (-1);
1580
1581 fp->stream.next_in = fp->cbuf;
1582 fp->stream.avail_in = bytes;
1583 }
1584
1585 /*
1586 * Decompress data from the buffer...
1587 */
1588
1589 fp->stream.next_out = (Bytef *)fp->buf;
1590 fp->stream.avail_out = sizeof(fp->buf);
1591
1592 if (inflate(&(fp->stream), Z_NO_FLUSH) == Z_STREAM_END)
1593 {
1594 /*
1595 * Read the CRC and length...
1596 */
1597
1598 unsigned char trailer[8]; /* Trailer bytes */
1599 uLong tcrc; /* Trailer CRC */
1600
1601
1602 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
1603 {
1604 /*
1605 * Can't get it, so mark end-of-file...
1606 */
1607
1608 fp->eof = 1;
1609 }
1610 else
1611 {
1612 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
1613 trailer[0];
1614
1615 if (tcrc != fp->crc)
1616 {
1617 /*
1618 * Bad CRC, mark end-of-file...
1619 */
1620
1621 fp->eof = 1;
1622
1623 return (-1);
1624 }
1625
1626 /*
1627 * Otherwise, reset the compressed flag so that we re-read the
1628 * file header...
1629 */
1630
1631 fp->compressed = 0;
1632 }
1633 }
1634
1635 bytes = sizeof(fp->buf) - fp->stream.avail_out;
1636
1637 /*
1638 * Return the decompressed data...
1639 */
1640
1641 fp->ptr = fp->buf;
1642 fp->end = fp->buf + bytes;
1643
1644 if (bytes)
1645 return (bytes);
1646 }
1647 }
1648 #endif /* HAVE_LIBZ */
1649
1650 /*
1651 * Read a buffer's full of data...
1652 */
1653
1654 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
1655 {
1656 /*
1657 * Can't read from file!
1658 */
1659
1660 fp->eof = 1;
1661 fp->ptr = fp->buf;
1662 fp->end = fp->buf;
1663
1664 return (-1);
1665 }
1666
1667 /*
1668 * Return the bytes we read...
1669 */
1670
1671 fp->eof = 0;
1672 fp->ptr = fp->buf;
1673 fp->end = fp->buf + bytes;
1674
1675 return (bytes);
1676 }
1677
1678
1679 /*
1680 * 'cups_read()' - Read from a file descriptor.
1681 */
1682
1683 static ssize_t /* O - Number of bytes read or -1 */
1684 cups_read(cups_file_t *fp, /* I - CUPS file */
1685 char *buf, /* I - Buffer */
1686 size_t bytes) /* I - Number bytes */
1687 {
1688 ssize_t total; /* Total bytes read */
1689
1690
1691 /*
1692 * Loop until we read at least 0 bytes...
1693 */
1694
1695 for (;;)
1696 {
1697 if (fp->mode == 's')
1698 total = recv(fp->fd, buf, bytes, 0);
1699 else
1700 total = read(fp->fd, buf, bytes);
1701
1702 if (total >= 0)
1703 break;
1704
1705 /*
1706 * Reads can be interrupted by signals and unavailable resources...
1707 */
1708
1709 if (errno == EAGAIN || errno == EINTR)
1710 continue;
1711 else
1712 return (-1);
1713 }
1714
1715 /*
1716 * Return the total number of bytes read...
1717 */
1718
1719 return (total);
1720 }
1721
1722
1723 /*
1724 * 'cups_write()' - Write to a file descriptor.
1725 */
1726
1727 static ssize_t /* O - Number of bytes written or -1 */
1728 cups_write(cups_file_t *fp, /* I - CUPS file */
1729 const char *buf, /* I - Buffer */
1730 size_t bytes) /* I - Number bytes */
1731 {
1732 size_t total, /* Total bytes written */
1733 count; /* Count this time */
1734
1735
1736 /*
1737 * Loop until all bytes are written...
1738 */
1739
1740 total = 0;
1741 while (bytes > 0)
1742 {
1743 if (fp->mode == 's')
1744 count = send(fp->fd, buf, bytes, 0);
1745 else
1746 count = write(fp->fd, buf, bytes);
1747
1748 if (count < 0)
1749 {
1750 /*
1751 * Writes can be interrupted by signals and unavailable resources...
1752 */
1753
1754 if (errno == EAGAIN || errno == EINTR)
1755 continue;
1756 else
1757 return (-1);
1758 }
1759
1760 /*
1761 * Update the counts for the last write call...
1762 */
1763
1764 bytes -= count;
1765 total += count;
1766 buf += count;
1767 }
1768
1769 /*
1770 * Return the total number of bytes written...
1771 */
1772
1773 return (total);
1774 }
1775
1776
1777 /*
1778 * End of "$Id: file.c 5057 2006-02-02 20:38:29Z mike $".
1779 */