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