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