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