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