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