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