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