]> git.ipfire.org Git - thirdparty/cups.git/blame - cups/file.c
Use httpAddrListen and new httpAddrClose in cupsd and other places that need it.
[thirdparty/cups.git] / cups / file.c
CommitLineData
ef416fc2 1/*
f2d18633 2 * "$Id$"
ef416fc2 3 *
71e16022 4 * File functions for CUPS.
ef416fc2 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 *
f3c17241 11 * Copyright 2007-2012 by Apple Inc.
b86bc4cf 12 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
ef416fc2 13 *
14 * These coded instructions, statements, and computer programs are the
bc44d920 15 * property of Apple Inc. and are protected by Federal copyright
16 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
17 * which should have been included with this file. If this file is
18 * file is missing or damaged, see the license at "http://www.cups.org/".
ef416fc2 19 *
20 * Contents:
21 *
22c9029b
MS
22 * _cupsFileCheck() - Check the permissions of the given filename.
23 * _cupsFileCheckFilter() - Report file check results as CUPS filter messages.
24 * cupsFileClose() - Close a CUPS file.
25 * cupsFileCompression() - Return whether a file is compressed.
26 * cupsFileEOF() - Return the end-of-file status.
27 * cupsFileFind() - Find a file using the specified path.
28 * cupsFileFlush() - Flush pending output.
29 * cupsFileGetChar() - Get a single character from a file.
30 * cupsFileGetConf() - Get a line from a configuration file.
31 * cupsFileGetLine() - Get a CR and/or LF-terminated line that may
32 * contain binary data.
33 * cupsFileGets() - Get a CR and/or LF-terminated line.
34 * cupsFileLock() - Temporarily lock access to a file.
35 * cupsFileNumber() - Return the file descriptor associated with a CUPS
36 * file.
37 * cupsFileOpen() - Open a CUPS file.
38 * cupsFileOpenFd() - Open a CUPS file using a file descriptor.
39 * cupsFilePeekChar() - Peek at the next character from a file.
40 * cupsFilePrintf() - Write a formatted string.
41 * cupsFilePutChar() - Write a character.
d4d03398 42 * cupsFilePutConf() - Write a configuration line.
22c9029b
MS
43 * cupsFilePuts() - Write a string.
44 * cupsFileRead() - Read from a file.
45 * cupsFileRewind() - Set the current file position to the beginning of
46 * the file.
47 * cupsFileSeek() - Seek in a file.
48 * cupsFileStderr() - Return a CUPS file associated with stderr.
49 * cupsFileStdin() - Return a CUPS file associated with stdin.
50 * cupsFileStdout() - Return a CUPS file associated with stdout.
51 * cupsFileTell() - Return the current file position.
52 * cupsFileUnlock() - Unlock access to a file.
53 * cupsFileWrite() - Write to a file.
54 * cups_compress() - Compress a buffer of data.
55 * cups_fill() - Fill the input buffer.
d4d03398 56 * cups_open() - Safely open a file for writing.
22c9029b
MS
57 * cups_read() - Read from a file descriptor.
58 * cups_write() - Write to a file descriptor.
ef416fc2 59 */
60
61/*
62 * Include necessary headers...
63 */
64
b9faaae1 65#include "file-private.h"
c7017ecc
MS
66#include <sys/stat.h>
67#include <sys/types.h>
ef416fc2 68
69
70/*
71 * Local functions...
72 */
73
74#ifdef HAVE_LIBZ
75static ssize_t cups_compress(cups_file_t *fp, const char *buf, size_t bytes);
76#endif /* HAVE_LIBZ */
77static ssize_t cups_fill(cups_file_t *fp);
c7017ecc 78static int cups_open(const char *filename, int mode);
ef416fc2 79static ssize_t cups_read(cups_file_t *fp, char *buf, size_t bytes);
80static ssize_t cups_write(cups_file_t *fp, const char *buf, size_t bytes);
81
82
83e08001 83#ifndef WIN32
22c9029b
MS
84/*
85 * '_cupsFileCheck()' - Check the permissions of the given filename.
86 */
87
88_cups_fc_result_t /* O - Check result */
89_cupsFileCheck(
90 const char *filename, /* I - Filename to check */
91 _cups_fc_filetype_t filetype, /* I - Type of file checks? */
92 int dorootchecks, /* I - Check for root permissions? */
93 _cups_fc_func_t cb, /* I - Callback function */
94 void *context) /* I - Context pointer for callback */
f228370c 95
22c9029b
MS
96{
97 struct stat fileinfo; /* File information */
98 char message[1024], /* Message string */
99 temp[1024], /* Parent directory filename */
100 *ptr; /* Pointer into parent directory */
101 _cups_fc_result_t result; /* Check result */
102
103
88f9aafc
MS
104 /*
105 * Does the filename contain a relative path ("../")?
106 */
107
108 if (strstr(filename, "../"))
109 {
110 /*
111 * Yes, fail it!
112 */
113
114 result = _CUPS_FILE_CHECK_RELATIVE_PATH;
115 goto finishup;
116 }
117
22c9029b
MS
118 /*
119 * Does the program even exist and is it accessible?
120 */
121
122 if (stat(filename, &fileinfo))
123 {
124 /*
125 * Nope...
126 */
127
128 result = _CUPS_FILE_CHECK_MISSING;
129 goto finishup;
130 }
131
132 /*
133 * Check the execute bit...
134 */
135
136 result = _CUPS_FILE_CHECK_OK;
137
138 switch (filetype)
139 {
140 case _CUPS_FILE_CHECK_DIRECTORY :
141 if (!S_ISDIR(fileinfo.st_mode))
142 result = _CUPS_FILE_CHECK_WRONG_TYPE;
143 break;
144
145 default :
146 if (!S_ISREG(fileinfo.st_mode))
147 result = _CUPS_FILE_CHECK_WRONG_TYPE;
148 break;
149 }
150
151 if (result)
152 goto finishup;
153
154 /*
155 * Are we doing root checks?
156 */
157
158 if (!dorootchecks)
159 {
160 /*
161 * Nope, so anything (else) goes...
162 */
163
164 goto finishup;
165 }
166
167 /*
168 * Verify permission of the file itself:
169 *
170 * 1. Must be owned by root
85dda01c 171 * 2. Must not be writable by group
22c9029b
MS
172 * 3. Must not be setuid
173 * 4. Must not be writable by others
174 */
175
176 if (fileinfo.st_uid || /* 1. Must be owned by root */
85dda01c 177 (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */
22c9029b
MS
178 (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
179 (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
180 {
181 result = _CUPS_FILE_CHECK_PERMISSIONS;
182 goto finishup;
183 }
184
185 if (filetype == _CUPS_FILE_CHECK_DIRECTORY ||
186 filetype == _CUPS_FILE_CHECK_FILE_ONLY)
187 goto finishup;
188
189 /*
190 * Now check the containing directory...
191 */
192
193 strlcpy(temp, filename, sizeof(temp));
194 if ((ptr = strrchr(temp, '/')) != NULL)
195 {
196 if (ptr == temp)
197 ptr[1] = '\0';
198 else
199 *ptr = '\0';
200 }
201
202 if (stat(temp, &fileinfo))
203 {
204 /*
205 * Doesn't exist?!?
206 */
207
208 result = _CUPS_FILE_CHECK_MISSING;
209 filetype = _CUPS_FILE_CHECK_DIRECTORY;
210 filename = temp;
211
212 goto finishup;
213 }
214
215 if (fileinfo.st_uid || /* 1. Must be owned by root */
85dda01c 216 (fileinfo.st_mode & S_IWGRP) || /* 2. Must not be writable by group */
22c9029b
MS
217 (fileinfo.st_mode & S_ISUID) || /* 3. Must not be setuid */
218 (fileinfo.st_mode & S_IWOTH)) /* 4. Must not be writable by others */
219 {
220 result = _CUPS_FILE_CHECK_PERMISSIONS;
221 filetype = _CUPS_FILE_CHECK_DIRECTORY;
222 filename = temp;
223 }
224
225 /*
226 * Common return point...
227 */
228
229 finishup:
230
231 if (cb)
232 {
233 cups_lang_t *lang = cupsLangDefault();
234 /* Localization information */
235
236 switch (result)
237 {
238 case _CUPS_FILE_CHECK_OK :
239 if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
240 snprintf(message, sizeof(message),
241 _cupsLangString(lang, _("Directory \"%s\" permissions OK "
242 "(0%o/uid=%d/gid=%d).")),
243 filename, fileinfo.st_mode, (int)fileinfo.st_uid,
244 (int)fileinfo.st_gid);
245 else
246 snprintf(message, sizeof(message),
247 _cupsLangString(lang, _("File \"%s\" permissions OK "
248 "(0%o/uid=%d/gid=%d).")),
249 filename, fileinfo.st_mode, (int)fileinfo.st_uid,
250 (int)fileinfo.st_gid);
251 break;
252
253 case _CUPS_FILE_CHECK_MISSING :
254 if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
255 snprintf(message, sizeof(message),
256 _cupsLangString(lang, _("Directory \"%s\" not available: "
257 "%s")),
258 filename, strerror(errno));
259 else
260 snprintf(message, sizeof(message),
261 _cupsLangString(lang, _("File \"%s\" not available: %s")),
262 filename, strerror(errno));
263 break;
264
265 case _CUPS_FILE_CHECK_PERMISSIONS :
266 if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
267 snprintf(message, sizeof(message),
268 _cupsLangString(lang, _("Directory \"%s\" has insecure "
269 "permissions "
270 "(0%o/uid=%d/gid=%d).")),
271 filename, fileinfo.st_mode, (int)fileinfo.st_uid,
272 (int)fileinfo.st_gid);
273 else
274 snprintf(message, sizeof(message),
275 _cupsLangString(lang, _("File \"%s\" has insecure "
276 "permissions "
277 "(0%o/uid=%d/gid=%d).")),
278 filename, fileinfo.st_mode, (int)fileinfo.st_uid,
279 (int)fileinfo.st_gid);
280 break;
281
282 case _CUPS_FILE_CHECK_WRONG_TYPE :
283 if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
284 snprintf(message, sizeof(message),
285 _cupsLangString(lang, _("Directory \"%s\" is a file.")),
286 filename);
287 else
288 snprintf(message, sizeof(message),
289 _cupsLangString(lang, _("File \"%s\" is a directory.")),
290 filename);
291 break;
88f9aafc
MS
292
293 case _CUPS_FILE_CHECK_RELATIVE_PATH :
294 if (filetype == _CUPS_FILE_CHECK_DIRECTORY)
295 snprintf(message, sizeof(message),
296 _cupsLangString(lang, _("Directory \"%s\" contains a "
297 "relative path.")), filename);
298 else
299 snprintf(message, sizeof(message),
300 _cupsLangString(lang, _("File \"%s\" contains a relative "
301 "path.")), filename);
302 break;
22c9029b
MS
303 }
304
305 (*cb)(context, result, message);
306 }
307
308 return (result);
309}
310
311
312/*
313 * '_cupsFileCheckFilter()' - Report file check results as CUPS filter messages.
314 */
315
316void
317_cupsFileCheckFilter(
318 void *context, /* I - Context pointer (unused) */
319 _cups_fc_result_t result, /* I - Result code */
320 const char *message) /* I - Message text */
321{
322 const char *prefix; /* Messaging prefix */
323
324
321d8d57
MS
325 (void)context;
326
22c9029b
MS
327 switch (result)
328 {
f228370c 329 default :
22c9029b
MS
330 case _CUPS_FILE_CHECK_OK :
331 prefix = "DEBUG2";
332 break;
333
334 case _CUPS_FILE_CHECK_MISSING :
335 case _CUPS_FILE_CHECK_WRONG_TYPE :
336 prefix = "ERROR";
337 fputs("STATE: +cups-missing-filter-warning\n", stderr);
338 break;
339
340 case _CUPS_FILE_CHECK_PERMISSIONS :
88f9aafc 341 case _CUPS_FILE_CHECK_RELATIVE_PATH :
22c9029b
MS
342 prefix = "ERROR";
343 fputs("STATE: +cups-insecure-filter-warning\n", stderr);
344 break;
345 }
346
347 fprintf(stderr, "%s: %s\n", prefix, message);
348}
83e08001 349#endif /* !WIN32 */
22c9029b
MS
350
351
ef416fc2 352/*
353 * 'cupsFileClose()' - Close a CUPS file.
5a738aea 354 *
f3c17241 355 * @since CUPS 1.2/OS X 10.5@
ef416fc2 356 */
357
358int /* O - 0 on success, -1 on error */
359cupsFileClose(cups_file_t *fp) /* I - CUPS file */
360{
361 int fd; /* File descriptor */
362 char mode; /* Open mode */
363 int status; /* Return status */
80ca4592 364 int is_stdio; /* Is a stdio file? */
ef416fc2 365
366
e07d4801 367 DEBUG_printf(("cupsFileClose(fp=%p)", fp));
ef416fc2 368
369 /*
370 * Range check...
371 */
372
373 if (!fp)
374 return (-1);
375
376 /*
377 * Flush pending write data...
378 */
379
380 if (fp->mode == 'w')
381 status = cupsFileFlush(fp);
382 else
383 status = 0;
384
385#ifdef HAVE_LIBZ
386 if (fp->compressed && status >= 0)
387 {
388 if (fp->mode == 'r')
389 {
390 /*
391 * Free decompression data...
392 */
393
394 inflateEnd(&fp->stream);
395 }
396 else
397 {
398 /*
399 * Flush any remaining compressed data...
400 */
401
402 unsigned char trailer[8]; /* Trailer CRC and length */
403 int done; /* Done writing... */
404
405
406 fp->stream.avail_in = 0;
407
408 for (done = 0;;)
409 {
410 if (fp->stream.next_out > fp->cbuf)
411 {
412 if (cups_write(fp, (char *)fp->cbuf,
413 fp->stream.next_out - fp->cbuf) < 0)
414 status = -1;
415
416 fp->stream.next_out = fp->cbuf;
417 fp->stream.avail_out = sizeof(fp->cbuf);
418 }
419
420 if (done || status < 0)
421 break;
422
423 done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END &&
424 fp->stream.next_out == fp->cbuf;
425 }
426
427 /*
428 * Write the CRC and length...
429 */
430
431 trailer[0] = fp->crc;
432 trailer[1] = fp->crc >> 8;
433 trailer[2] = fp->crc >> 16;
434 trailer[3] = fp->crc >> 24;
435 trailer[4] = fp->pos;
436 trailer[5] = fp->pos >> 8;
437 trailer[6] = fp->pos >> 16;
438 trailer[7] = fp->pos >> 24;
439
440 if (cups_write(fp, (char *)trailer, 8) < 0)
441 status = -1;
442
443 /*
444 * Free all memory used by the compression stream...
445 */
446
447 deflateEnd(&(fp->stream));
448 }
449 }
450#endif /* HAVE_LIBZ */
451
452 /*
453 * Save the file descriptor we used and free memory...
454 */
455
80ca4592 456 fd = fp->fd;
457 mode = fp->mode;
458 is_stdio = fp->is_stdio;
ef416fc2 459
75bd9771
MS
460 if (fp->printf_buffer)
461 free(fp->printf_buffer);
462
ef416fc2 463 free(fp);
464
465 /*
466 * Close the file, returning the close status...
467 */
468
469 if (mode == 's')
470 {
87e98392 471 if (httpAddrClose(NULL, fd) < 0)
ef416fc2 472 status = -1;
473 }
80ca4592 474 else if (!is_stdio)
ef416fc2 475 {
476 if (close(fd) < 0)
477 status = -1;
478 }
479
480 return (status);
481}
482
483
484/*
485 * 'cupsFileCompression()' - Return whether a file is compressed.
5a738aea 486 *
f3c17241 487 * @since CUPS 1.2/OS X 10.5@
ef416fc2 488 */
489
5a738aea 490int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */
ef416fc2 491cupsFileCompression(cups_file_t *fp) /* I - CUPS file */
492{
80ca4592 493 return (fp ? fp->compressed : CUPS_FILE_NONE);
ef416fc2 494}
495
496
497/*
498 * 'cupsFileEOF()' - Return the end-of-file status.
5a738aea 499 *
f3c17241 500 * @since CUPS 1.2/OS X 10.5@
ef416fc2 501 */
502
5a738aea 503int /* O - 1 on end of file, 0 otherwise */
ef416fc2 504cupsFileEOF(cups_file_t *fp) /* I - CUPS file */
505{
80ca4592 506 return (fp ? fp->eof : 1);
ef416fc2 507}
508
509
fa73b229 510/*
511 * 'cupsFileFind()' - Find a file using the specified path.
512 *
513 * This function allows the paths in the path string to be separated by
514 * colons (UNIX standard) or semicolons (Windows standard) and stores the
515 * result in the buffer supplied. If the file cannot be found in any of
5a738aea
MS
516 * the supplied paths, @code NULL@ is returned. A @code NULL@ path only
517 * matches the current directory.
518 *
f3c17241 519 * @since CUPS 1.2/OS X 10.5@
fa73b229 520 */
521
5a738aea 522const char * /* O - Full path to file or @code NULL@ if not found */
fa73b229 523cupsFileFind(const char *filename, /* I - File to find */
524 const char *path, /* I - Colon/semicolon-separated path */
4400e98d 525 int executable, /* I - 1 = executable files, 0 = any file/dir */
526 char *buffer, /* I - Filename buffer */
fa73b229 527 int bufsize) /* I - Size of filename buffer */
528{
529 char *bufptr, /* Current position in buffer */
530 *bufend; /* End of buffer */
531
532
533 /*
534 * Range check input...
535 */
536
e07d4801
MS
537 DEBUG_printf(("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, "
538 "buffer=%p, bufsize=%d)", filename, path, executable, buffer,
539 bufsize));
540
fa73b229 541 if (!filename || !buffer || bufsize < 2)
542 return (NULL);
543
544 if (!path)
545 {
546 /*
547 * No path, so check current directory...
548 */
549
550 if (!access(filename, 0))
551 {
552 strlcpy(buffer, filename, bufsize);
553 return (buffer);
554 }
555 else
556 return (NULL);
557 }
558
559 /*
560 * Now check each path and return the first match...
561 */
562
563 bufend = buffer + bufsize - 1;
564 bufptr = buffer;
565
566 while (*path)
567 {
b86bc4cf 568#ifdef WIN32
569 if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255))))
570#else
fa73b229 571 if (*path == ';' || *path == ':')
b86bc4cf 572#endif /* WIN32 */
fa73b229 573 {
574 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
575 *bufptr++ = '/';
576
577 strlcpy(bufptr, filename, bufend - bufptr);
578
4400e98d 579#ifdef WIN32
fa73b229 580 if (!access(buffer, 0))
4400e98d 581#else
582 if (!access(buffer, executable ? X_OK : 0))
583#endif /* WIN32 */
b86bc4cf 584 {
e07d4801 585 DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
fa73b229 586 return (buffer);
b86bc4cf 587 }
fa73b229 588
589 bufptr = buffer;
590 }
591 else if (bufptr < bufend)
592 *bufptr++ = *path;
593
594 path ++;
595 }
596
597 /*
598 * Check the last path...
599 */
600
601 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend)
602 *bufptr++ = '/';
603
604 strlcpy(bufptr, filename, bufend - bufptr);
605
606 if (!access(buffer, 0))
b86bc4cf 607 {
e07d4801 608 DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer));
fa73b229 609 return (buffer);
b86bc4cf 610 }
fa73b229 611 else
b86bc4cf 612 {
e07d4801 613 DEBUG_puts("1cupsFileFind: Returning NULL");
fa73b229 614 return (NULL);
b86bc4cf 615 }
fa73b229 616}
617
618
ef416fc2 619/*
620 * 'cupsFileFlush()' - Flush pending output.
5a738aea 621 *
f3c17241 622 * @since CUPS 1.2/OS X 10.5@
ef416fc2 623 */
624
625int /* O - 0 on success, -1 on error */
626cupsFileFlush(cups_file_t *fp) /* I - CUPS file */
627{
2abf387c 628 ssize_t bytes; /* Bytes to write */
ef416fc2 629
630
e07d4801 631 DEBUG_printf(("cupsFileFlush(fp=%p)", fp));
ef416fc2 632
633 /*
634 * Range check input...
635 */
636
637 if (!fp || fp->mode != 'w')
638 {
e07d4801 639 DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file...");
ef416fc2 640 return (-1);
641 }
642
b86bc4cf 643 bytes = (ssize_t)(fp->ptr - fp->buf);
ef416fc2 644
e07d4801 645 DEBUG_printf(("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...",
634763e8 646 CUPS_LLCAST bytes));
ecdc0628 647
ef416fc2 648 if (bytes > 0)
649 {
650#ifdef HAVE_LIBZ
651 if (fp->compressed)
652 bytes = cups_compress(fp, fp->buf, bytes);
653 else
654#endif /* HAVE_LIBZ */
655 bytes = cups_write(fp, fp->buf, bytes);
656
657 if (bytes < 0)
658 return (-1);
659
660 fp->ptr = fp->buf;
661 }
f14324a7 662
ef416fc2 663 return (0);
664}
665
666
667/*
668 * 'cupsFileGetChar()' - Get a single character from a file.
5a738aea 669 *
f3c17241 670 * @since CUPS 1.2/OS X 10.5@
ef416fc2 671 */
672
5a738aea 673int /* O - Character or -1 on end of file */
ef416fc2 674cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */
675{
676 /*
677 * Range check input...
678 */
679
680 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
b86bc4cf 681 {
f14324a7 682 DEBUG_puts("5cupsFileGetChar: Bad arguments!");
ef416fc2 683 return (-1);
b86bc4cf 684 }
ef416fc2 685
686 /*
687 * If the input buffer is empty, try to read more data...
688 */
689
690 if (fp->ptr >= fp->end)
691 if (cups_fill(fp) < 0)
b86bc4cf 692 {
f14324a7 693 DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!");
ef416fc2 694 return (-1);
b86bc4cf 695 }
ef416fc2 696
697 /*
698 * Return the next character in the buffer...
699 */
700
f14324a7 701 DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255));
b86bc4cf 702
634763e8
MS
703 fp->pos ++;
704
f14324a7 705 DEBUG_printf(("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 706
ef416fc2 707 return (*(fp->ptr)++ & 255);
708}
709
710
711/*
22c9029b 712 * 'cupsFileGetConf()' - Get a line from a configuration file.
5a738aea 713 *
f3c17241 714 * @since CUPS 1.2/OS X 10.5@
ef416fc2 715 */
716
5a738aea 717char * /* O - Line read or @code NULL@ on end of file or error */
ef416fc2 718cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */
719 char *buf, /* O - String buffer */
720 size_t buflen, /* I - Size of string buffer */
721 char **value, /* O - Pointer to value */
722 int *linenum) /* IO - Current line number */
723{
724 char *ptr; /* Pointer into line */
725
726
727 /*
728 * Range check input...
729 */
730
e07d4801
MS
731 DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT
732 ", value=%p, linenum=%p)", fp, buf, CUPS_LLCAST buflen,
634763e8
MS
733 value, linenum));
734
ef416fc2 735 if (!fp || (fp->mode != 'r' && fp->mode != 's') ||
736 !buf || buflen < 2 || !value)
737 {
738 if (value)
739 *value = NULL;
740
741 return (NULL);
742 }
743
744 /*
745 * Read the next non-comment line...
746 */
747
748 *value = NULL;
f7deaa1a 749
ef416fc2 750 while (cupsFileGets(fp, buf, buflen))
751 {
752 (*linenum) ++;
753
754 /*
755 * Strip any comments...
756 */
757
758 if ((ptr = strchr(buf, '#')) != NULL)
759 {
f7deaa1a 760 if (ptr > buf && ptr[-1] == '\\')
ef416fc2 761 {
f7deaa1a 762 // Unquote the #...
763 _cups_strcpy(ptr - 1, ptr);
ef416fc2 764 }
f7deaa1a 765 else
766 {
767 // Strip the comment and any trailing whitespace...
768 while (ptr > buf)
769 {
7cf5915e 770 if (!_cups_isspace(ptr[-1]))
f7deaa1a 771 break;
772
773 ptr --;
774 }
ef416fc2 775
f7deaa1a 776 *ptr = '\0';
777 }
ef416fc2 778 }
779
780 /*
781 * Strip leading whitespace...
782 */
783
7cf5915e 784 for (ptr = buf; _cups_isspace(*ptr); ptr ++);
ef416fc2 785
786 if (ptr > buf)
787 _cups_strcpy(buf, ptr);
788
789 /*
790 * See if there is anything left...
791 */
792
793 if (buf[0])
794 {
795 /*
796 * Yes, grab any value and return...
797 */
798
799 for (ptr = buf; *ptr; ptr ++)
7cf5915e 800 if (_cups_isspace(*ptr))
ef416fc2 801 break;
802
803 if (*ptr)
804 {
805 /*
806 * Have a value, skip any other spaces...
807 */
808
7cf5915e 809 while (_cups_isspace(*ptr))
ef416fc2 810 *ptr++ = '\0';
811
812 if (*ptr)
813 *value = ptr;
814
815 /*
816 * Strip trailing whitespace and > for lines that begin with <...
817 */
818
819 ptr += strlen(ptr) - 1;
820
821 if (buf[0] == '<' && *ptr == '>')
822 *ptr-- = '\0';
823 else if (buf[0] == '<' && *ptr != '>')
824 {
825 /*
826 * Syntax error...
827 */
828
829 *value = NULL;
830 return (buf);
831 }
832
7cf5915e 833 while (ptr > *value && _cups_isspace(*ptr))
ef416fc2 834 *ptr-- = '\0';
835 }
836
837 /*
838 * Return the line...
839 */
840
841 return (buf);
842 }
843 }
844
845 return (NULL);
846}
847
848
80ca4592 849/*
850 * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may
851 * contain binary data.
852 *
5a738aea
MS
853 * This function differs from @link cupsFileGets@ in that the trailing CR
854 * and LF are preserved, as is any binary data on the line. The buffer is
855 * nul-terminated, however you should use the returned length to determine
80ca4592 856 * the number of bytes on the line.
5a738aea 857 *
f3c17241 858 * @since CUPS 1.2/OS X 10.5@
80ca4592 859 */
860
5a738aea 861size_t /* O - Number of bytes on line or 0 on end of file */
80ca4592 862cupsFileGetLine(cups_file_t *fp, /* I - File to read from */
863 char *buf, /* I - Buffer */
864 size_t buflen) /* I - Size of buffer */
865{
866 int ch; /* Character from file */
867 char *ptr, /* Current position in line buffer */
868 *end; /* End of line buffer */
869
870
871 /*
872 * Range check input...
873 */
874
e07d4801 875 DEBUG_printf(("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")",
634763e8
MS
876 fp, buf, CUPS_LLCAST buflen));
877
80ca4592 878 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3)
879 return (0);
880
881 /*
882 * Now loop until we have a valid line...
883 */
884
885 for (ptr = buf, end = buf + buflen - 2; ptr < end ;)
886 {
887 if (fp->ptr >= fp->end)
888 if (cups_fill(fp) <= 0)
889 break;
890
891 *ptr++ = ch = *(fp->ptr)++;
634763e8 892 fp->pos ++;
80ca4592 893
894 if (ch == '\r')
895 {
896 /*
897 * Check for CR LF...
898 */
899
900 if (fp->ptr >= fp->end)
901 if (cups_fill(fp) <= 0)
902 break;
903
904 if (*(fp->ptr) == '\n')
634763e8 905 {
80ca4592 906 *ptr++ = *(fp->ptr)++;
634763e8
MS
907 fp->pos ++;
908 }
80ca4592 909
910 break;
911 }
912 else if (ch == '\n')
913 {
914 /*
915 * Line feed ends a line...
916 */
917
918 break;
919 }
920 }
921
922 *ptr = '\0';
923
e07d4801 924 DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 925
80ca4592 926 return (ptr - buf);
927}
928
929
ef416fc2 930/*
931 * 'cupsFileGets()' - Get a CR and/or LF-terminated line.
5a738aea 932 *
f3c17241 933 * @since CUPS 1.2/OS X 10.5@
ef416fc2 934 */
935
5a738aea 936char * /* O - Line read or @code NULL@ on end of file or error */
ef416fc2 937cupsFileGets(cups_file_t *fp, /* I - CUPS file */
938 char *buf, /* O - String buffer */
939 size_t buflen) /* I - Size of string buffer */
940{
941 int ch; /* Character from file */
942 char *ptr, /* Current position in line buffer */
943 *end; /* End of line buffer */
944
945
946 /*
947 * Range check input...
948 */
949
e07d4801 950 DEBUG_printf(("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", fp, buf,
634763e8
MS
951 CUPS_LLCAST buflen));
952
ef416fc2 953 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 2)
954 return (NULL);
955
956 /*
957 * Now loop until we have a valid line...
958 */
959
960 for (ptr = buf, end = buf + buflen - 1; ptr < end ;)
961 {
962 if (fp->ptr >= fp->end)
963 if (cups_fill(fp) <= 0)
964 {
965 if (ptr == buf)
966 return (NULL);
967 else
968 break;
969 }
970
971 ch = *(fp->ptr)++;
634763e8 972 fp->pos ++;
ef416fc2 973
974 if (ch == '\r')
975 {
976 /*
977 * Check for CR LF...
978 */
979
980 if (fp->ptr >= fp->end)
981 if (cups_fill(fp) <= 0)
982 break;
983
984 if (*(fp->ptr) == '\n')
634763e8
MS
985 {
986 fp->ptr ++;
987 fp->pos ++;
988 }
ef416fc2 989
990 break;
991 }
992 else if (ch == '\n')
993 {
994 /*
995 * Line feed ends a line...
996 */
997
998 break;
999 }
1000 else
1001 *ptr++ = ch;
1002 }
1003
1004 *ptr = '\0';
1005
e07d4801 1006 DEBUG_printf(("4cupsFileGets: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1007
ef416fc2 1008 return (buf);
1009}
1010
1011
1012/*
1013 * 'cupsFileLock()' - Temporarily lock access to a file.
5a738aea 1014 *
f3c17241 1015 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1016 */
1017
1018int /* O - 0 on success, -1 on error */
5a738aea 1019cupsFileLock(cups_file_t *fp, /* I - CUPS file */
ef416fc2 1020 int block) /* I - 1 to wait for the lock, 0 to fail right away */
1021{
1022 /*
1023 * Range check...
1024 */
1025
1026 if (!fp || fp->mode == 's')
1027 return (-1);
1028
1029 /*
1030 * Try the lock...
1031 */
1032
1033#ifdef WIN32
536bc2c6 1034 return (_locking(fp->fd, block ? _LK_LOCK : _LK_NBLCK, 0));
ef416fc2 1035#else
1036 return (lockf(fp->fd, block ? F_LOCK : F_TLOCK, 0));
1037#endif /* WIN32 */
1038}
1039
1040
1041/*
1042 * 'cupsFileNumber()' - Return the file descriptor associated with a CUPS file.
5a738aea 1043 *
f3c17241 1044 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1045 */
1046
1047int /* O - File descriptor */
1048cupsFileNumber(cups_file_t *fp) /* I - CUPS file */
1049{
5a738aea
MS
1050 if (fp)
1051 return (fp->fd);
1052 else
1053 return (-1);
ef416fc2 1054}
1055
1056
1057/*
1058 * 'cupsFileOpen()' - Open a CUPS file.
5a738aea
MS
1059 *
1060 * The "mode" parameter can be "r" to read, "w" to write, overwriting any
1061 * existing file, "a" to append to an existing file or create a new file,
1062 * or "s" to open a socket connection.
1063 *
634763e8
MS
1064 * When opening for writing ("w"), an optional number from 1 to 9 can be
1065 * supplied which enables Flate compression of the file. Compression is
1066 * not supported for the "a" (append) mode.
5a738aea
MS
1067 *
1068 * When opening a socket connection, the filename is a string of the form
1069 * "address:port" or "hostname:port". The socket will make an IPv4 or IPv6
1070 * connection as needed, generally preferring IPv6 connections when there is
1071 * a choice.
1072 *
f3c17241 1073 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1074 */
1075
5a738aea 1076cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */
ef416fc2 1077cupsFileOpen(const char *filename, /* I - Name of file */
1078 const char *mode) /* I - Open mode */
1079{
1080 cups_file_t *fp; /* New CUPS file */
1081 int fd; /* File descriptor */
1082 char hostname[1024], /* Hostname */
1083 *portname; /* Port "name" (number or service) */
1084 http_addrlist_t *addrlist; /* Host address list */
1085
1086
e07d4801 1087 DEBUG_printf(("cupsFileOpen(filename=\"%s\", mode=\"%s\")", filename,
b423cd4c 1088 mode));
1089
ef416fc2 1090 /*
1091 * Range check input...
1092 */
1093
1094 if (!filename || !mode ||
634763e8
MS
1095 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
1096 (*mode == 'a' && isdigit(mode[1] & 255)))
ef416fc2 1097 return (NULL);
1098
1099 /*
1100 * Open the file...
1101 */
1102
1103 switch (*mode)
1104 {
1105 case 'a' : /* Append file */
c7017ecc
MS
1106 fd = cups_open(filename,
1107 O_RDWR | O_CREAT | O_APPEND | O_LARGEFILE | O_BINARY);
ef416fc2 1108 break;
1109
1110 case 'r' : /* Read file */
b86bc4cf 1111 fd = open(filename, O_RDONLY | O_LARGEFILE | O_BINARY, 0);
ef416fc2 1112 break;
1113
1114 case 'w' : /* Write file */
c7017ecc
MS
1115 fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
1116 if (fd < 0 && errno == ENOENT)
1117 {
1118 fd = cups_open(filename,
1119 O_WRONLY | O_CREAT | O_EXCL | O_LARGEFILE | O_BINARY);
1120 if (fd < 0 && errno == EEXIST)
1121 fd = cups_open(filename, O_WRONLY | O_LARGEFILE | O_BINARY);
1122 }
1123
1124 if (fd >= 0)
1125#ifdef WIN32
1126 _chsize(fd, 0);
1127#else
1128 ftruncate(fd, 0);
1129#endif /* WIN32 */
ef416fc2 1130 break;
1131
1132 case 's' : /* Read/write socket */
1133 strlcpy(hostname, filename, sizeof(hostname));
1134 if ((portname = strrchr(hostname, ':')) != NULL)
1135 *portname++ = '\0';
1136 else
1137 return (NULL);
1138
1139 /*
1140 * Lookup the hostname and service...
1141 */
1142
1143 if ((addrlist = httpAddrGetList(hostname, AF_UNSPEC, portname)) == NULL)
1144 return (NULL);
1145
1146 /*
1147 * Connect to the server...
1148 */
1149
1150 if (!httpAddrConnect(addrlist, &fd))
1151 {
1152 httpAddrFreeList(addrlist);
1153 return (NULL);
1154 }
1155
1156 httpAddrFreeList(addrlist);
1157 break;
1158
1159 default : /* Remove bogus compiler warning... */
1160 return (NULL);
1161 }
1162
1163 if (fd < 0)
1164 return (NULL);
1165
1166 /*
1167 * Create the CUPS file structure...
1168 */
1169
1170 if ((fp = cupsFileOpenFd(fd, mode)) == NULL)
1171 {
1172 if (*mode == 's')
87e98392 1173 httpAddrClose(NULL, fd);
ef416fc2 1174 else
1175 close(fd);
1176 }
1177
1178 /*
1179 * Return it...
1180 */
1181
1182 return (fp);
1183}
1184
1185/*
1186 * 'cupsFileOpenFd()' - Open a CUPS file using a file descriptor.
5a738aea 1187 *
634763e8
MS
1188 * The "mode" parameter can be "r" to read, "w" to write, "a" to append,
1189 * or "s" to treat the file descriptor as a bidirectional socket connection.
5a738aea 1190 *
634763e8
MS
1191 * When opening for writing ("w"), an optional number from 1 to 9 can be
1192 * supplied which enables Flate compression of the file. Compression is
1193 * not supported for the "a" (append) mode.
5a738aea 1194 *
f3c17241 1195 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1196 */
1197
5a738aea 1198cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */
ef416fc2 1199cupsFileOpenFd(int fd, /* I - File descriptor */
1200 const char *mode) /* I - Open mode */
1201{
1202 cups_file_t *fp; /* New CUPS file */
1203
1204
e07d4801 1205 DEBUG_printf(("cupsFileOpenFd(fd=%d, mode=\"%s\")", fd, mode));
b423cd4c 1206
ef416fc2 1207 /*
1208 * Range check input...
1209 */
1210
1211 if (fd < 0 || !mode ||
634763e8
MS
1212 (*mode != 'r' && *mode != 'w' && *mode != 'a' && *mode != 's') ||
1213 (*mode == 'a' && isdigit(mode[1] & 255)))
ef416fc2 1214 return (NULL);
1215
1216 /*
1217 * Allocate memory...
1218 */
1219
1220 if ((fp = calloc(1, sizeof(cups_file_t))) == NULL)
1221 return (NULL);
1222
1223 /*
1224 * Open the file...
1225 */
1226
1227 fp->fd = fd;
1228
1229 switch (*mode)
1230 {
ef416fc2 1231 case 'a' :
634763e8
MS
1232 fp->pos = lseek(fd, 0, SEEK_END);
1233
1234 case 'w' :
ef416fc2 1235 fp->mode = 'w';
1236 fp->ptr = fp->buf;
1237 fp->end = fp->buf + sizeof(fp->buf);
1238
1239#ifdef HAVE_LIBZ
1240 if (mode[1] >= '1' && mode[1] <= '9')
1241 {
1242 /*
1243 * Open a compressed stream, so write the standard gzip file
1244 * header...
1245 */
1246
1247 unsigned char header[10]; /* gzip file header */
1248 time_t curtime; /* Current time */
1249
1250
1251 curtime = time(NULL);
1252 header[0] = 0x1f;
1253 header[1] = 0x8b;
1254 header[2] = Z_DEFLATED;
1255 header[3] = 0;
1256 header[4] = curtime;
1257 header[5] = curtime >> 8;
1258 header[6] = curtime >> 16;
1259 header[7] = curtime >> 24;
1260 header[8] = 0;
1261 header[9] = 0x03;
1262
1263 cups_write(fp, (char *)header, 10);
1264
1265 /*
1266 * Initialize the compressor...
1267 */
1268
1269 deflateInit2(&(fp->stream), mode[1] - '0', Z_DEFLATED, -15, 8,
1270 Z_DEFAULT_STRATEGY);
1271
1272 fp->stream.next_out = fp->cbuf;
1273 fp->stream.avail_out = sizeof(fp->cbuf);
1274 fp->compressed = 1;
1275 fp->crc = crc32(0L, Z_NULL, 0);
1276 }
1277#endif /* HAVE_LIBZ */
1278 break;
1279
1280 case 'r' :
1281 fp->mode = 'r';
1282 break;
1283
1284 case 's' :
1285 fp->mode = 's';
1286 break;
1287
1288 default : /* Remove bogus compiler warning... */
1289 return (NULL);
1290 }
1291
1292 /*
1293 * Don't pass this file to child processes...
1294 */
1295
1296#ifndef WIN32
1297 fcntl(fp->fd, F_SETFD, fcntl(fp->fd, F_GETFD) | FD_CLOEXEC);
1298#endif /* !WIN32 */
1299
1300 return (fp);
1301}
1302
1303
1304/*
1305 * 'cupsFilePeekChar()' - Peek at the next character from a file.
5a738aea 1306 *
f3c17241 1307 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1308 */
1309
5a738aea 1310int /* O - Character or -1 on end of file */
ef416fc2 1311cupsFilePeekChar(cups_file_t *fp) /* I - CUPS file */
1312{
1313 /*
1314 * Range check input...
1315 */
1316
1317 if (!fp || (fp->mode != 'r' && fp->mode != 's'))
1318 return (-1);
1319
1320 /*
1321 * If the input buffer is empty, try to read more data...
1322 */
1323
1324 if (fp->ptr >= fp->end)
1325 if (cups_fill(fp) < 0)
1326 return (-1);
1327
1328 /*
1329 * Return the next character in the buffer...
1330 */
1331
1332 return (*(fp->ptr) & 255);
1333}
1334
1335
1336/*
1337 * 'cupsFilePrintf()' - Write a formatted string.
5a738aea 1338 *
f3c17241 1339 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1340 */
1341
5a738aea 1342int /* O - Number of bytes written or -1 on error */
ef416fc2 1343cupsFilePrintf(cups_file_t *fp, /* I - CUPS file */
1344 const char *format, /* I - Printf-style format string */
1345 ...) /* I - Additional args as necessary */
1346{
1347 va_list ap; /* Argument list */
2abf387c 1348 ssize_t bytes; /* Formatted size */
ecdc0628 1349
ef416fc2 1350
e07d4801 1351 DEBUG_printf(("2cupsFilePrintf(fp=%p, format=\"%s\", ...)", fp, format));
ef416fc2 1352
1353 if (!fp || !format || (fp->mode != 'w' && fp->mode != 's'))
1354 return (-1);
1355
75bd9771
MS
1356 if (!fp->printf_buffer)
1357 {
1358 /*
1359 * Start with an 1k printf buffer...
1360 */
1361
1362 if ((fp->printf_buffer = malloc(1024)) == NULL)
1363 return (-1);
1364
1365 fp->printf_size = 1024;
1366 }
1367
ef416fc2 1368 va_start(ap, format);
75bd9771 1369 bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
ef416fc2 1370 va_end(ap);
1371
536bc2c6 1372 if (bytes >= (ssize_t)fp->printf_size)
75bd9771
MS
1373 {
1374 /*
1375 * Expand the printf buffer...
1376 */
1377
1378 char *temp; /* Temporary buffer pointer */
1379
1380
1381 if (bytes > 65535)
1382 return (-1);
1383
1384 if ((temp = realloc(fp->printf_buffer, bytes + 1)) == NULL)
1385 return (-1);
1386
1387 fp->printf_buffer = temp;
1388 fp->printf_size = bytes + 1;
1389
1390 va_start(ap, format);
1391 bytes = vsnprintf(fp->printf_buffer, fp->printf_size, format, ap);
1392 va_end(ap);
1393 }
ecdc0628 1394
ef416fc2 1395 if (fp->mode == 's')
634763e8 1396 {
75bd9771 1397 if (cups_write(fp, fp->printf_buffer, bytes) < 0)
634763e8
MS
1398 return (-1);
1399
1400 fp->pos += bytes;
1401
e07d4801 1402 DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8
MS
1403
1404 return (bytes);
1405 }
ef416fc2 1406
1407 if ((fp->ptr + bytes) > fp->end)
1408 if (cupsFileFlush(fp))
1409 return (-1);
1410
1411 fp->pos += bytes;
1412
e07d4801 1413 DEBUG_printf(("4cupsFilePrintf: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1414
ef416fc2 1415 if (bytes > sizeof(fp->buf))
1416 {
1417#ifdef HAVE_LIBZ
1418 if (fp->compressed)
75bd9771 1419 return (cups_compress(fp, fp->printf_buffer, bytes));
ef416fc2 1420 else
1421#endif /* HAVE_LIBZ */
75bd9771 1422 return (cups_write(fp, fp->printf_buffer, bytes));
ef416fc2 1423 }
1424 else
1425 {
75bd9771 1426 memcpy(fp->ptr, fp->printf_buffer, bytes);
ef416fc2 1427 fp->ptr += bytes;
1428 return (bytes);
1429 }
1430}
1431
1432
1433/*
1434 * 'cupsFilePutChar()' - Write a character.
5a738aea 1435 *
f3c17241 1436 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1437 */
1438
1439int /* O - 0 on success, -1 on error */
1440cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */
1441 int c) /* I - Character to write */
1442{
1443 /*
1444 * Range check input...
1445 */
1446
1447 if (!fp || (fp->mode != 'w' && fp->mode != 's'))
1448 return (-1);
1449
1450 if (fp->mode == 's')
1451 {
1452 /*
1453 * Send character immediately over socket...
1454 */
1455
1456 char ch; /* Output character */
1457
1458
1459 ch = c;
1460
1461 if (send(fp->fd, &ch, 1, 0) < 1)
1462 return (-1);
1463 }
1464 else
1465 {
1466 /*
1467 * Buffer it up...
1468 */
1469
1470 if (fp->ptr >= fp->end)
1471 if (cupsFileFlush(fp))
1472 return (-1);
1473
1474 *(fp->ptr) ++ = c;
1475 }
1476
1477 fp->pos ++;
1478
e07d4801 1479 DEBUG_printf(("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1480
ef416fc2 1481 return (0);
1482}
1483
1484
58dc1933
MS
1485/*
1486 * 'cupsFilePutConf()' - Write a configuration line.
1487 *
1488 * This function handles any comment escaping of the value.
1489 *
f3c17241 1490 * @since CUPS 1.4/OS X 10.6@
58dc1933
MS
1491 */
1492
1493ssize_t /* O - Number of bytes written or -1 on error */
1494cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */
1495 const char *directive, /* I - Directive */
1496 const char *value) /* I - Value */
1497{
1498 ssize_t bytes, /* Number of bytes written */
1499 temp; /* Temporary byte count */
1500 const char *ptr; /* Pointer into value */
1501
1502
1503 if (!fp || !directive || !*directive)
1504 return (-1);
1505
1506 if ((bytes = cupsFilePuts(fp, directive)) < 0)
1507 return (-1);
1508
1509 if (cupsFilePutChar(fp, ' ') < 0)
1510 return (-1);
1511 bytes ++;
1512
1513 if (value && *value)
1514 {
1515 if ((ptr = strchr(value, '#')) != NULL)
1516 {
1517 /*
1518 * Need to quote the first # in the info string...
1519 */
1520
1521 if ((temp = cupsFileWrite(fp, value, ptr - value)) < 0)
1522 return (-1);
1523 bytes += temp;
1524
1525 if (cupsFilePutChar(fp, '\\') < 0)
1526 return (-1);
1527 bytes ++;
1528
1529 if ((temp = cupsFilePuts(fp, ptr)) < 0)
1530 return (-1);
1531 bytes += temp;
1532 }
1533 else if ((temp = cupsFilePuts(fp, value)) < 0)
1534 return (-1);
1535 else
1536 bytes += temp;
1537 }
1538
1539 if (cupsFilePutChar(fp, '\n') < 0)
1540 return (-1);
1541 else
1542 return (bytes + 1);
1543}
1544
1545
ef416fc2 1546/*
1547 * 'cupsFilePuts()' - Write a string.
5a738aea
MS
1548 *
1549 * Like the @code fputs@ function, no newline is appended to the string.
1550 *
f3c17241 1551 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1552 */
1553
5a738aea 1554int /* O - Number of bytes written or -1 on error */
ef416fc2 1555cupsFilePuts(cups_file_t *fp, /* I - CUPS file */
1556 const char *s) /* I - String to write */
1557{
2abf387c 1558 ssize_t bytes; /* Bytes to write */
ef416fc2 1559
1560
1561 /*
1562 * Range check input...
1563 */
1564
1565 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's'))
1566 return (-1);
1567
1568 /*
1569 * Write the string...
1570 */
1571
b86bc4cf 1572 bytes = (int)strlen(s);
ef416fc2 1573
1574 if (fp->mode == 's')
1575 {
1576 if (cups_write(fp, s, bytes) < 0)
1577 return (-1);
1578
1579 fp->pos += bytes;
1580
e07d4801 1581 DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1582
ef416fc2 1583 return (bytes);
1584 }
1585
1586 if ((fp->ptr + bytes) > fp->end)
1587 if (cupsFileFlush(fp))
1588 return (-1);
1589
1590 fp->pos += bytes;
1591
e07d4801 1592 DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1593
ef416fc2 1594 if (bytes > sizeof(fp->buf))
1595 {
1596#ifdef HAVE_LIBZ
1597 if (fp->compressed)
1598 return (cups_compress(fp, s, bytes));
1599 else
1600#endif /* HAVE_LIBZ */
1601 return (cups_write(fp, s, bytes));
1602 }
1603 else
1604 {
1605 memcpy(fp->ptr, s, bytes);
1606 fp->ptr += bytes;
1607 return (bytes);
1608 }
1609}
1610
1611
1612/*
1613 * 'cupsFileRead()' - Read from a file.
5a738aea 1614 *
f3c17241 1615 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1616 */
1617
5a738aea 1618ssize_t /* O - Number of bytes read or -1 on error */
ef416fc2 1619cupsFileRead(cups_file_t *fp, /* I - CUPS file */
1620 char *buf, /* O - Buffer */
1621 size_t bytes) /* I - Number of bytes to read */
1622{
2abf387c 1623 size_t total; /* Total bytes read */
1624 ssize_t count; /* Bytes read */
ef416fc2 1625
1626
e07d4801 1627 DEBUG_printf(("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
634763e8 1628 CUPS_LLCAST bytes));
ef416fc2 1629
1630 /*
1631 * Range check input...
1632 */
1633
82f97232 1634 if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's'))
ef416fc2 1635 return (-1);
1636
1637 if (bytes == 0)
1638 return (0);
1639
1640 /*
1641 * Loop until all bytes are read...
1642 */
1643
1644 total = 0;
1645 while (bytes > 0)
1646 {
1647 if (fp->ptr >= fp->end)
1648 if (cups_fill(fp) <= 0)
1649 {
e07d4801
MS
1650 DEBUG_printf(("4cupsFileRead: cups_fill() returned -1, total="
1651 CUPS_LLFMT, CUPS_LLCAST total));
ef416fc2 1652
1653 if (total > 0)
b86bc4cf 1654 return ((ssize_t)total);
ef416fc2 1655 else
1656 return (-1);
1657 }
1658
b86bc4cf 1659 count = (ssize_t)(fp->end - fp->ptr);
1660 if (count > (ssize_t)bytes)
1661 count = (ssize_t)bytes;
ef416fc2 1662
1663 memcpy(buf, fp->ptr, count);
1664 fp->ptr += count;
634763e8
MS
1665 fp->pos += count;
1666
e07d4801 1667 DEBUG_printf(("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
ef416fc2 1668
1669 /*
1670 * Update the counts for the last read...
1671 */
1672
1673 bytes -= count;
1674 total += count;
1675 buf += count;
1676 }
1677
1678 /*
1679 * Return the total number of bytes read...
1680 */
1681
e07d4801 1682 DEBUG_printf(("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total));
ef416fc2 1683
b86bc4cf 1684 return ((ssize_t)total);
ef416fc2 1685}
1686
1687
1688/*
5a738aea
MS
1689 * 'cupsFileRewind()' - Set the current file position to the beginning of the
1690 * file.
1691 *
f3c17241 1692 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1693 */
1694
5a738aea 1695off_t /* O - New file position or -1 on error */
ef416fc2 1696cupsFileRewind(cups_file_t *fp) /* I - CUPS file */
1697{
80ca4592 1698 /*
1699 * Range check input...
1700 */
1701
e07d4801
MS
1702 DEBUG_printf(("cupsFileRewind(fp=%p)", fp));
1703 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1704
80ca4592 1705 if (!fp || fp->mode != 'r')
1706 return (-1);
1707
1708 /*
1709 * Handle special cases...
1710 */
1711
634763e8 1712 if (fp->bufpos == 0)
80ca4592 1713 {
1714 /*
1715 * No seeking necessary...
1716 */
1717
634763e8
MS
1718 fp->pos = 0;
1719
80ca4592 1720 if (fp->ptr)
1721 {
1722 fp->ptr = fp->buf;
1723 fp->eof = 0;
1724 }
1725
e07d4801 1726 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 1727
80ca4592 1728 return (0);
1729 }
1730
1731 /*
1732 * Otherwise, seek in the file and cleanup any compression buffers...
1733 */
1734
1735#ifdef HAVE_LIBZ
1736 if (fp->compressed)
1737 {
1738 inflateEnd(&fp->stream);
1739 fp->compressed = 0;
1740 }
1741#endif /* HAVE_LIBZ */
1742
c9fc04c6
MS
1743 if (lseek(fp->fd, 0, SEEK_SET))
1744 {
e07d4801 1745 DEBUG_printf(("1cupsFileRewind: lseek failed: %s", strerror(errno)));
c9fc04c6
MS
1746 return (-1);
1747 }
80ca4592 1748
634763e8
MS
1749 fp->bufpos = 0;
1750 fp->pos = 0;
1751 fp->ptr = NULL;
1752 fp->end = NULL;
1753 fp->eof = 0;
1754
e07d4801 1755 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
80ca4592 1756
1757 return (0);
ef416fc2 1758}
1759
1760
1761/*
1762 * 'cupsFileSeek()' - Seek in a file.
5a738aea 1763 *
f3c17241 1764 * @since CUPS 1.2/OS X 10.5@
ef416fc2 1765 */
1766
5a738aea 1767off_t /* O - New file position or -1 on error */
ef416fc2 1768cupsFileSeek(cups_file_t *fp, /* I - CUPS file */
1769 off_t pos) /* I - Position in file */
1770{
2abf387c 1771 ssize_t bytes; /* Number bytes in buffer */
ef416fc2 1772
1773
e07d4801 1774 DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", fp,
634763e8 1775 CUPS_LLCAST pos));
e07d4801
MS
1776 DEBUG_printf(("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
1777 DEBUG_printf(("2cupsFileSeek: fp->ptr=%p, fp->end=%p", fp->ptr, fp->end));
ef416fc2 1778
1779 /*
1780 * Range check input...
1781 */
1782
1783 if (!fp || pos < 0 || fp->mode != 'r')
1784 return (-1);
1785
80ca4592 1786 /*
1787 * Handle special cases...
1788 */
1789
1790 if (pos == 0)
1791 return (cupsFileRewind(fp));
1792
634763e8 1793 if (fp->ptr)
b423cd4c 1794 {
634763e8 1795 bytes = (ssize_t)(fp->end - fp->buf);
b423cd4c 1796
e07d4801 1797 DEBUG_printf(("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes));
c168a833 1798
634763e8 1799 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
b423cd4c 1800 {
634763e8
MS
1801 /*
1802 * No seeking necessary...
1803 */
1804
1805 fp->pos = pos;
1806 fp->ptr = fp->buf + pos - fp->bufpos;
b423cd4c 1807 fp->eof = 0;
b423cd4c 1808
634763e8
MS
1809 return (pos);
1810 }
b423cd4c 1811 }
1812
80ca4592 1813#ifdef HAVE_LIBZ
1814 if (!fp->compressed && !fp->ptr)
1815 {
1816 /*
1817 * Preload a buffer to determine whether the file is compressed...
1818 */
1819
1820 if (cups_fill(fp) < 0)
1821 return (-1);
1822 }
1823#endif /* HAVE_LIBZ */
1824
ef416fc2 1825 /*
634763e8 1826 * Seek forwards or backwards...
ef416fc2 1827 */
1828
ef416fc2 1829 fp->eof = 0;
1830
634763e8 1831 if (pos < fp->bufpos)
ef416fc2 1832 {
1833 /*
1834 * Need to seek backwards...
1835 */
1836
e07d4801 1837 DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS");
80ca4592 1838
ef416fc2 1839#ifdef HAVE_LIBZ
1840 if (fp->compressed)
1841 {
1842 inflateEnd(&fp->stream);
1843
1844 lseek(fp->fd, 0, SEEK_SET);
634763e8
MS
1845 fp->bufpos = 0;
1846 fp->pos = 0;
1847 fp->ptr = NULL;
1848 fp->end = NULL;
ef416fc2 1849
1850 while ((bytes = cups_fill(fp)) > 0)
634763e8 1851 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
ef416fc2 1852 break;
1853
1854 if (bytes <= 0)
1855 return (-1);
80ca4592 1856
634763e8
MS
1857 fp->ptr = fp->buf + pos - fp->bufpos;
1858 fp->pos = pos;
ef416fc2 1859 }
1860 else
1861#endif /* HAVE_LIBZ */
1862 {
634763e8
MS
1863 fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1864 fp->pos = fp->bufpos;
1865 fp->ptr = NULL;
1866 fp->end = NULL;
80ca4592 1867
e07d4801 1868 DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
634763e8 1869 CUPS_LLCAST fp->pos));
ef416fc2 1870 }
1871 }
634763e8 1872 else
ef416fc2 1873 {
1874 /*
1875 * Need to seek forwards...
1876 */
1877
e07d4801 1878 DEBUG_puts("2cupsFileSeek: SEEK FORWARDS");
80ca4592 1879
ef416fc2 1880#ifdef HAVE_LIBZ
80ca4592 1881 if (fp->compressed)
ef416fc2 1882 {
1883 while ((bytes = cups_fill(fp)) > 0)
80ca4592 1884 {
634763e8 1885 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes))
ef416fc2 1886 break;
80ca4592 1887 }
ef416fc2 1888
1889 if (bytes <= 0)
1890 return (-1);
80ca4592 1891
634763e8
MS
1892 fp->ptr = fp->buf + pos - fp->bufpos;
1893 fp->pos = pos;
ef416fc2 1894 }
1895 else
1896#endif /* HAVE_LIBZ */
1897 {
634763e8
MS
1898 fp->bufpos = lseek(fp->fd, pos, SEEK_SET);
1899 fp->pos = fp->bufpos;
1900 fp->ptr = NULL;
1901 fp->end = NULL;
80ca4592 1902
e07d4801 1903 DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT,
634763e8 1904 CUPS_LLCAST fp->pos));
ef416fc2 1905 }
1906 }
ef416fc2 1907
e07d4801 1908 DEBUG_printf(("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
ef416fc2 1909
1910 return (fp->pos);
1911}
1912
1913
80ca4592 1914/*
1915 * 'cupsFileStderr()' - Return a CUPS file associated with stderr.
5a738aea 1916 *
f3c17241 1917 * @since CUPS 1.2/OS X 10.5@
80ca4592 1918 */
1919
5a738aea 1920cups_file_t * /* O - CUPS file */
80ca4592 1921cupsFileStderr(void)
1922{
1923 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1924
1925
1926 /*
1927 * Open file descriptor 2 as needed...
1928 */
1929
1930 if (!cg->stdio_files[2])
1931 {
1932 /*
1933 * Flush any pending output on the stdio file...
1934 */
1935
1936 fflush(stderr);
1937
1938 /*
1939 * Open file descriptor 2...
1940 */
1941
1942 if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL)
1943 cg->stdio_files[2]->is_stdio = 1;
1944 }
1945
1946 return (cg->stdio_files[2]);
1947}
1948
1949
1950/*
1951 * 'cupsFileStdin()' - Return a CUPS file associated with stdin.
5a738aea 1952 *
f3c17241 1953 * @since CUPS 1.2/OS X 10.5@
80ca4592 1954 */
1955
5a738aea 1956cups_file_t * /* O - CUPS file */
80ca4592 1957cupsFileStdin(void)
1958{
1959 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1960
1961
1962 /*
1963 * Open file descriptor 0 as needed...
1964 */
1965
1966 if (!cg->stdio_files[0])
1967 {
1968 /*
1969 * Open file descriptor 0...
1970 */
1971
1972 if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL)
1973 cg->stdio_files[0]->is_stdio = 1;
1974 }
1975
1976 return (cg->stdio_files[0]);
1977}
1978
1979
1980/*
1981 * 'cupsFileStdout()' - Return a CUPS file associated with stdout.
5a738aea 1982 *
f3c17241 1983 * @since CUPS 1.2/OS X 10.5@
80ca4592 1984 */
1985
5a738aea 1986cups_file_t * /* O - CUPS file */
80ca4592 1987cupsFileStdout(void)
1988{
1989 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */
1990
1991
1992 /*
1993 * Open file descriptor 1 as needed...
1994 */
1995
1996 if (!cg->stdio_files[1])
1997 {
1998 /*
1999 * Flush any pending output on the stdio file...
2000 */
2001
2002 fflush(stdout);
2003
2004 /*
2005 * Open file descriptor 1...
2006 */
2007
2008 if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL)
2009 cg->stdio_files[1]->is_stdio = 1;
2010 }
2011
2012 return (cg->stdio_files[1]);
2013}
2014
2015
ef416fc2 2016/*
2017 * 'cupsFileTell()' - Return the current file position.
5a738aea 2018 *
f3c17241 2019 * @since CUPS 1.2/OS X 10.5@
ef416fc2 2020 */
2021
2022off_t /* O - File position */
2023cupsFileTell(cups_file_t *fp) /* I - CUPS file */
2024{
e07d4801
MS
2025 DEBUG_printf(("2cupsFileTell(fp=%p)", fp));
2026 DEBUG_printf(("3cupsFileTell: pos=" CUPS_LLFMT,
2027 CUPS_LLCAST (fp ? fp->pos : -1)));
634763e8 2028
80ca4592 2029 return (fp ? fp->pos : 0);
ef416fc2 2030}
2031
2032
2033/*
2034 * 'cupsFileUnlock()' - Unlock access to a file.
5a738aea 2035 *
f3c17241 2036 * @since CUPS 1.2/OS X 10.5@
ef416fc2 2037 */
2038
2039int /* O - 0 on success, -1 on error */
5a738aea 2040cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */
ef416fc2 2041{
2042 /*
2043 * Range check...
2044 */
2045
e07d4801 2046 DEBUG_printf(("cupsFileUnlock(fp=%p)", fp));
634763e8 2047
ef416fc2 2048 if (!fp || fp->mode == 's')
2049 return (-1);
2050
2051 /*
2052 * Unlock...
2053 */
2054
2055#ifdef WIN32
536bc2c6 2056 return (_locking(fp->fd, _LK_UNLCK, 0));
ef416fc2 2057#else
2058 return (lockf(fp->fd, F_ULOCK, 0));
2059#endif /* WIN32 */
2060}
2061
2062
2063/*
2064 * 'cupsFileWrite()' - Write to a file.
5a738aea 2065 *
f3c17241 2066 * @since CUPS 1.2/OS X 10.5@
ef416fc2 2067 */
2068
5a738aea 2069ssize_t /* O - Number of bytes written or -1 on error */
ef416fc2 2070cupsFileWrite(cups_file_t *fp, /* I - CUPS file */
2071 const char *buf, /* I - Buffer */
2072 size_t bytes) /* I - Number of bytes to write */
2073{
2074 /*
2075 * Range check input...
2076 */
2077
e07d4801 2078 DEBUG_printf(("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")",
634763e8
MS
2079 fp, buf, CUPS_LLCAST bytes));
2080
82f97232 2081 if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's'))
ef416fc2 2082 return (-1);
2083
2084 if (bytes == 0)
2085 return (0);
2086
2087 /*
2088 * Write the buffer...
2089 */
2090
2091 if (fp->mode == 's')
2092 {
2093 if (cups_write(fp, buf, bytes) < 0)
2094 return (-1);
2095
b86bc4cf 2096 fp->pos += (off_t)bytes;
ef416fc2 2097
e07d4801 2098 DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 2099
b86bc4cf 2100 return ((ssize_t)bytes);
ef416fc2 2101 }
2102
2103 if ((fp->ptr + bytes) > fp->end)
2104 if (cupsFileFlush(fp))
2105 return (-1);
2106
b86bc4cf 2107 fp->pos += (off_t)bytes;
ef416fc2 2108
e07d4801 2109 DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos));
634763e8 2110
ef416fc2 2111 if (bytes > sizeof(fp->buf))
2112 {
2113#ifdef HAVE_LIBZ
2114 if (fp->compressed)
2115 return (cups_compress(fp, buf, bytes));
2116 else
2117#endif /* HAVE_LIBZ */
2118 return (cups_write(fp, buf, bytes));
2119 }
2120 else
2121 {
2122 memcpy(fp->ptr, buf, bytes);
2123 fp->ptr += bytes;
b86bc4cf 2124 return ((ssize_t)bytes);
ef416fc2 2125 }
2126}
2127
2128
2129#ifdef HAVE_LIBZ
2130/*
22c9029b 2131 * 'cups_compress()' - Compress a buffer of data.
ef416fc2 2132 */
2133
2134static ssize_t /* O - Number of bytes written or -1 */
2135cups_compress(cups_file_t *fp, /* I - CUPS file */
2136 const char *buf, /* I - Buffer */
2137 size_t bytes) /* I - Number bytes */
2138{
e07d4801 2139 DEBUG_printf(("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
634763e8 2140 CUPS_LLCAST bytes));
ecdc0628 2141
ef416fc2 2142 /*
2143 * Update the CRC...
2144 */
2145
2146 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes);
2147
2148 /*
2149 * Deflate the bytes...
2150 */
2151
2152 fp->stream.next_in = (Bytef *)buf;
2153 fp->stream.avail_in = bytes;
2154
2155 while (fp->stream.avail_in > 0)
2156 {
2157 /*
2158 * Flush the current buffer...
2159 */
2160
e07d4801 2161 DEBUG_printf(("9cups_compress: avail_in=%d, avail_out=%d",
634763e8 2162 fp->stream.avail_in, fp->stream.avail_out));
ecdc0628 2163
ef416fc2 2164 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8))
2165 {
2166 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0)
2167 return (-1);
ecdc0628 2168
2169 fp->stream.next_out = fp->cbuf;
2170 fp->stream.avail_out = sizeof(fp->cbuf);
ef416fc2 2171 }
2172
2173 deflate(&(fp->stream), Z_NO_FLUSH);
2174 }
2175
2176 return (bytes);
2177}
2178#endif /* HAVE_LIBZ */
2179
2180
2181/*
22c9029b 2182 * 'cups_fill()' - Fill the input buffer.
ef416fc2 2183 */
2184
2185static ssize_t /* O - Number of bytes or -1 */
2186cups_fill(cups_file_t *fp) /* I - CUPS file */
2187{
2188 ssize_t bytes; /* Number of bytes read */
2189#ifdef HAVE_LIBZ
c277e2f8 2190 int status; /* Decompression status */
ef416fc2 2191 const unsigned char *ptr, /* Pointer into buffer */
2192 *end; /* End of buffer */
2193#endif /* HAVE_LIBZ */
2194
2195
e07d4801
MS
2196 DEBUG_printf(("7cups_fill(fp=%p)", fp));
2197 DEBUG_printf(("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, "
2198 "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d",
634763e8 2199 fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof));
ef416fc2 2200
2201 if (fp->ptr && fp->end)
c9fc04c6 2202 fp->bufpos += fp->end - fp->buf;
ef416fc2 2203
2204#ifdef HAVE_LIBZ
e07d4801 2205 DEBUG_printf(("9cups_fill: fp->compressed=%d", fp->compressed));
b423cd4c 2206
ef416fc2 2207 while (!fp->ptr || fp->compressed)
2208 {
2209 /*
2210 * Check to see if we have read any data yet; if not, see if we have a
2211 * compressed file...
2212 */
2213
2214 if (!fp->ptr)
2215 {
2216 /*
2217 * Reset the file position in case we are seeking...
2218 */
2219
2220 fp->compressed = 0;
ef416fc2 2221
2222 /*
2223 * Read the first bytes in the file to determine if we have a gzip'd
2224 * file...
2225 */
2226
fa73b229 2227 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0)
ef416fc2 2228 {
2229 /*
2230 * Can't read from file!
2231 */
2232
e07d4801 2233 DEBUG_printf(("9cups_fill: cups_read() returned " CUPS_LLFMT,
b423cd4c 2234 CUPS_LLCAST bytes));
2235
ef416fc2 2236 return (-1);
2237 }
2238
fa73b229 2239 if (bytes < 10 || fp->buf[0] != 0x1f ||
e00b005a 2240 (fp->buf[1] & 255) != 0x8b ||
fa73b229 2241 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0)
ef416fc2 2242 {
2243 /*
2244 * Not a gzip'd file!
2245 */
2246
ef416fc2 2247 fp->ptr = fp->buf;
2248 fp->end = fp->buf + bytes;
2249
e07d4801 2250 DEBUG_printf(("9cups_fill: Returning " CUPS_LLFMT,
c9fc04c6 2251 CUPS_LLCAST bytes));
b423cd4c 2252
ef416fc2 2253 return (bytes);
2254 }
2255
2256 /*
2257 * Parse header junk: extra data, original name, and comment...
2258 */
2259
fa73b229 2260 ptr = (unsigned char *)fp->buf + 10;
2261 end = (unsigned char *)fp->buf + bytes;
ef416fc2 2262
fa73b229 2263 if (fp->buf[3] & 0x04)
ef416fc2 2264 {
2265 /*
2266 * Skip extra data...
2267 */
2268
2269 if ((ptr + 2) > end)
2270 {
2271 /*
2272 * Can't read from file!
2273 */
2274
2275 return (-1);
2276 }
2277
2278 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0];
2279 ptr += 2 + bytes;
2280
2281 if (ptr > end)
2282 {
2283 /*
2284 * Can't read from file!
2285 */
2286
2287 return (-1);
2288 }
2289 }
2290
fa73b229 2291 if (fp->buf[3] & 0x08)
ef416fc2 2292 {
2293 /*
2294 * Skip original name data...
2295 */
2296
2297 while (ptr < end && *ptr)
2298 ptr ++;
2299
2300 if (ptr < end)
2301 ptr ++;
2302 else
2303 {
2304 /*
2305 * Can't read from file!
2306 */
2307
2308 return (-1);
2309 }
2310 }
2311
fa73b229 2312 if (fp->buf[3] & 0x10)
ef416fc2 2313 {
2314 /*
2315 * Skip comment data...
2316 */
2317
2318 while (ptr < end && *ptr)
2319 ptr ++;
2320
2321 if (ptr < end)
2322 ptr ++;
2323 else
2324 {
2325 /*
2326 * Can't read from file!
2327 */
2328
2329 return (-1);
2330 }
2331 }
2332
fa73b229 2333 if (fp->buf[3] & 0x02)
ef416fc2 2334 {
2335 /*
2336 * Skip header CRC data...
2337 */
2338
2339 ptr += 2;
2340
2341 if (ptr > end)
2342 {
2343 /*
2344 * Can't read from file!
2345 */
2346
2347 return (-1);
2348 }
2349 }
2350
fa73b229 2351 /*
2352 * Copy the flate-compressed data to the compression buffer...
2353 */
2354
2355 if ((bytes = end - ptr) > 0)
2356 memcpy(fp->cbuf, ptr, bytes);
2357
ef416fc2 2358 /*
2359 * Setup the decompressor data...
2360 */
2361
2362 fp->stream.zalloc = (alloc_func)0;
2363 fp->stream.zfree = (free_func)0;
2364 fp->stream.opaque = (voidpf)0;
fa73b229 2365 fp->stream.next_in = (Bytef *)fp->cbuf;
ef416fc2 2366 fp->stream.next_out = NULL;
fa73b229 2367 fp->stream.avail_in = bytes;
ef416fc2 2368 fp->stream.avail_out = 0;
2369 fp->crc = crc32(0L, Z_NULL, 0);
2370
2371 if (inflateInit2(&(fp->stream), -15) != Z_OK)
2372 return (-1);
2373
2374 fp->compressed = 1;
2375 }
2376
2377 if (fp->compressed)
2378 {
2379 /*
2380 * If we have reached end-of-file, return immediately...
2381 */
2382
2383 if (fp->eof)
2384 return (-1);
2385
2386 /*
2387 * Fill the decompression buffer as needed...
2388 */
2389
2390 if (fp->stream.avail_in == 0)
2391 {
2392 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0)
2393 return (-1);
2394
2395 fp->stream.next_in = fp->cbuf;
2396 fp->stream.avail_in = bytes;
2397 }
2398
2399 /*
2400 * Decompress data from the buffer...
2401 */
2402
2403 fp->stream.next_out = (Bytef *)fp->buf;
2404 fp->stream.avail_out = sizeof(fp->buf);
2405
c277e2f8
MS
2406 status = inflate(&(fp->stream), Z_NO_FLUSH);
2407
2408 if (fp->stream.next_out > (Bytef *)fp->buf)
2409 fp->crc = crc32(fp->crc, (Bytef *)fp->buf,
2410 fp->stream.next_out - (Bytef *)fp->buf);
2411
2412 if (status == Z_STREAM_END)
ef416fc2 2413 {
2414 /*
2415 * Read the CRC and length...
2416 */
2417
2418 unsigned char trailer[8]; /* Trailer bytes */
2419 uLong tcrc; /* Trailer CRC */
2420
2421
2422 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer))
2423 {
2424 /*
2425 * Can't get it, so mark end-of-file...
2426 */
2427
2428 fp->eof = 1;
ef416fc2 2429 }
fa73b229 2430 else
2431 {
2432 tcrc = (((((trailer[3] << 8) | trailer[2]) << 8) | trailer[1]) << 8) |
2433 trailer[0];
ef416fc2 2434
fa73b229 2435 if (tcrc != fp->crc)
2436 {
2437 /*
2438 * Bad CRC, mark end-of-file...
2439 */
2440
e07d4801 2441 DEBUG_printf(("9cups_fill: tcrc=%08x, fp->crc=%08x",
c277e2f8
MS
2442 (unsigned int)tcrc, (unsigned int)fp->crc));
2443
fa73b229 2444 fp->eof = 1;
2445
2446 return (-1);
2447 }
ef416fc2 2448
ef416fc2 2449 /*
fa73b229 2450 * Otherwise, reset the compressed flag so that we re-read the
2451 * file header...
ef416fc2 2452 */
ef416fc2 2453
fa73b229 2454 fp->compressed = 0;
ef416fc2 2455 }
ef416fc2 2456 }
2457
2458 bytes = sizeof(fp->buf) - fp->stream.avail_out;
2459
2460 /*
2461 * Return the decompressed data...
2462 */
2463
2464 fp->ptr = fp->buf;
2465 fp->end = fp->buf + bytes;
2466
fa73b229 2467 if (bytes)
2468 return (bytes);
ef416fc2 2469 }
2470 }
2471#endif /* HAVE_LIBZ */
2472
2473 /*
2474 * Read a buffer's full of data...
2475 */
2476
2477 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0)
2478 {
2479 /*
2480 * Can't read from file!
2481 */
2482
2483 fp->eof = 1;
2484 fp->ptr = fp->buf;
2485 fp->end = fp->buf;
2486
2487 return (-1);
2488 }
2489
2490 /*
2491 * Return the bytes we read...
2492 */
2493
2494 fp->eof = 0;
2495 fp->ptr = fp->buf;
2496 fp->end = fp->buf + bytes;
2497
2498 return (bytes);
2499}
2500
2501
c7017ecc
MS
2502/*
2503 * 'cups_open()' - Safely open a file for writing.
2504 *
2505 * We don't allow appending to directories or files that are hard-linked or
2506 * symlinked.
2507 */
2508
2509static int /* O - File descriptor or -1 otherwise */
2510cups_open(const char *filename, /* I - Filename */
2511 int mode) /* I - Open mode */
2512{
2513 int fd; /* File descriptor */
2514 struct stat fileinfo; /* File information */
2515#ifndef WIN32
2516 struct stat linkinfo; /* Link information */
2517#endif /* !WIN32 */
2518
2519
2520 /*
2521 * Open the file...
2522 */
2523
2524 if ((fd = open(filename, mode, 0666)) < 0)
2525 return (-1);
2526
2527 /*
2528 * Then verify that the file descriptor doesn't point to a directory or hard-
2529 * linked file.
2530 */
2531
2532 if (fstat(fd, &fileinfo))
2533 {
2534 close(fd);
2535 return (-1);
2536 }
2537
2538 if (fileinfo.st_nlink != 1)
2539 {
2540 close(fd);
2541 errno = EPERM;
2542 return (-1);
2543 }
2544
2545#ifdef WIN32
2546 if (fileinfo.st_mode & _S_IFDIR)
2547#else
2548 if (S_ISDIR(fileinfo.st_mode))
2549#endif /* WIN32 */
2550 {
2551 close(fd);
2552 errno = EISDIR;
2553 return (-1);
2554 }
2555
2556#ifndef WIN32
2557 /*
2558 * Then use lstat to determine whether the filename is a symlink...
2559 */
2560
2561 if (lstat(filename, &linkinfo))
2562 {
2563 close(fd);
2564 return (-1);
2565 }
2566
2567 if (S_ISLNK(linkinfo.st_mode) ||
2568 fileinfo.st_dev != linkinfo.st_dev ||
2569 fileinfo.st_ino != linkinfo.st_ino ||
2570#ifdef HAVE_ST_GEN
2571 fileinfo.st_gen != linkinfo.st_gen ||
2572#endif /* HAVE_ST_GEN */
2573 fileinfo.st_nlink != linkinfo.st_nlink ||
2574 fileinfo.st_mode != linkinfo.st_mode)
2575 {
2576 /*
2577 * Yes, don't allow!
2578 */
2579
2580 close(fd);
2581 errno = EPERM;
2582 return (-1);
2583 }
2584#endif /* !WIN32 */
2585
2586 return (fd);
2587}
2588
2589
ef416fc2 2590/*
2591 * 'cups_read()' - Read from a file descriptor.
2592 */
2593
2594static ssize_t /* O - Number of bytes read or -1 */
2595cups_read(cups_file_t *fp, /* I - CUPS file */
2596 char *buf, /* I - Buffer */
2597 size_t bytes) /* I - Number bytes */
2598{
2599 ssize_t total; /* Total bytes read */
2600
2601
e07d4801 2602 DEBUG_printf(("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
634763e8
MS
2603 CUPS_LLCAST bytes));
2604
ef416fc2 2605 /*
2606 * Loop until we read at least 0 bytes...
2607 */
2608
2609 for (;;)
2610 {
b86bc4cf 2611#ifdef WIN32
2612 if (fp->mode == 's')
2613 total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0);
2614 else
2615 total = (ssize_t)read(fp->fd, buf, (unsigned)bytes);
2616#else
ef416fc2 2617 if (fp->mode == 's')
2618 total = recv(fp->fd, buf, bytes, 0);
2619 else
2620 total = read(fp->fd, buf, bytes);
b86bc4cf 2621#endif /* WIN32 */
ef416fc2 2622
e07d4801 2623 DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total));
634763e8 2624
ef416fc2 2625 if (total >= 0)
2626 break;
2627
2628 /*
2629 * Reads can be interrupted by signals and unavailable resources...
2630 */
2631
2632 if (errno == EAGAIN || errno == EINTR)
2633 continue;
2634 else
2635 return (-1);
2636 }
2637
2638 /*
2639 * Return the total number of bytes read...
2640 */
2641
2642 return (total);
2643}
2644
2645
2646/*
2647 * 'cups_write()' - Write to a file descriptor.
2648 */
2649
2650static ssize_t /* O - Number of bytes written or -1 */
2651cups_write(cups_file_t *fp, /* I - CUPS file */
2652 const char *buf, /* I - Buffer */
2653 size_t bytes) /* I - Number bytes */
2654{
2abf387c 2655 size_t total; /* Total bytes written */
2656 ssize_t count; /* Count this time */
ef416fc2 2657
2658
e07d4801 2659 DEBUG_printf(("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf,
634763e8 2660 CUPS_LLCAST bytes));
ecdc0628 2661
ef416fc2 2662 /*
2663 * Loop until all bytes are written...
2664 */
2665
2666 total = 0;
2667 while (bytes > 0)
2668 {
b86bc4cf 2669#ifdef WIN32
2670 if (fp->mode == 's')
2671 count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0);
2672 else
2673 count = (ssize_t)write(fp->fd, buf, (unsigned)bytes);
2674#else
ef416fc2 2675 if (fp->mode == 's')
2676 count = send(fp->fd, buf, bytes, 0);
2677 else
2678 count = write(fp->fd, buf, bytes);
b86bc4cf 2679#endif /* WIN32 */
ef416fc2 2680
e07d4801 2681 DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count));
634763e8 2682
ef416fc2 2683 if (count < 0)
2684 {
2685 /*
2686 * Writes can be interrupted by signals and unavailable resources...
2687 */
2688
2689 if (errno == EAGAIN || errno == EINTR)
2690 continue;
2691 else
2692 return (-1);
2693 }
2694
2695 /*
2696 * Update the counts for the last write call...
2697 */
2698
2699 bytes -= count;
2700 total += count;
2701 buf += count;
2702 }
2703
2704 /*
2705 * Return the total number of bytes written...
2706 */
2707
b86bc4cf 2708 return ((ssize_t)total);
ef416fc2 2709}
2710
2711
2712/*
f2d18633 2713 * End of "$Id$".
ef416fc2 2714 */