1/* 2 * "$Id: file.c 11693 2014-03-11 01:24:45Z 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-2013 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 default : 292 case _CUPS_FILE_CHECK_OK : 293 prefix = "DEBUG2"; 294 break; 295 296 case _CUPS_FILE_CHECK_MISSING : 297 case _CUPS_FILE_CHECK_WRONG_TYPE : 298 prefix = "ERROR"; 299 fputs("STATE: +cups-missing-filter-warning\n", stderr); 300 break; 301 302 case _CUPS_FILE_CHECK_PERMISSIONS : 303 case _CUPS_FILE_CHECK_RELATIVE_PATH : 304 prefix = "ERROR"; 305 fputs("STATE: +cups-insecure-filter-warning\n", stderr); 306 break; 307 } 308 309 fprintf(stderr, "%s: %s\n", prefix, message); 310} 311#endif /* !WIN32 */ 312 313 314/* 315 * 'cupsFileClose()' - Close a CUPS file. 316 * 317 * @since CUPS 1.2/OS X 10.5@ 318 */ 319 320int /* O - 0 on success, -1 on error */ 321cupsFileClose(cups_file_t *fp) /* I - CUPS file */ 322{ 323 int fd; /* File descriptor */ 324 char mode; /* Open mode */ 325 int status; /* Return status */ 326 int is_stdio; /* Is a stdio file? */ 327 328 329 DEBUG_printf(("cupsFileClose(fp=%p)", fp)); 330 331 /* 332 * Range check... 333 */ 334 335 if (!fp) 336 return (-1); 337 338 /* 339 * Flush pending write data... 340 */ 341 342 if (fp->mode == 'w') 343 status = cupsFileFlush(fp); 344 else 345 status = 0; 346 347#ifdef HAVE_LIBZ 348 if (fp->compressed && status >= 0) 349 { 350 if (fp->mode == 'r') 351 { 352 /* 353 * Free decompression data... 354 */ 355 356 inflateEnd(&fp->stream); 357 } 358 else 359 { 360 /* 361 * Flush any remaining compressed data... 362 */ 363 364 unsigned char trailer[8]; /* Trailer CRC and length */ 365 int done; /* Done writing... */ 366 367 368 fp->stream.avail_in = 0; 369 370 for (done = 0;;) 371 { 372 if (fp->stream.next_out > fp->cbuf) 373 { 374 if (cups_write(fp, (char *)fp->cbuf, 375 fp->stream.next_out - fp->cbuf) < 0) 376 status = -1; 377 378 fp->stream.next_out = fp->cbuf; 379 fp->stream.avail_out = sizeof(fp->cbuf); 380 } 381 382 if (done || status < 0) 383 break; 384 385 done = deflate(&fp->stream, Z_FINISH) == Z_STREAM_END && 386 fp->stream.next_out == fp->cbuf; 387 } 388 389 /* 390 * Write the CRC and length... 391 */ 392 393 trailer[0] = fp->crc; 394 trailer[1] = fp->crc >> 8; 395 trailer[2] = fp->crc >> 16; 396 trailer[3] = fp->crc >> 24; 397 trailer[4] = fp->pos; 398 trailer[5] = fp->pos >> 8; 399 trailer[6] = fp->pos >> 16; 400 trailer[7] = fp->pos >> 24; 401 402 if (cups_write(fp, (char *)trailer, 8) < 0) 403 status = -1; 404 405 /* 406 * Free all memory used by the compression stream... 407 */ 408 409 deflateEnd(&(fp->stream)); 410 } 411 } 412#endif /* HAVE_LIBZ */ 413 414 /* 415 * Save the file descriptor we used and free memory... 416 */ 417 418 fd = fp->fd; 419 mode = fp->mode; 420 is_stdio = fp->is_stdio; 421 422 if (fp->printf_buffer) 423 free(fp->printf_buffer); 424 425 free(fp); 426 427 /* 428 * Close the file, returning the close status... 429 */ 430 431 if (mode == 's') 432 { 433 if (closesocket(fd) < 0) 434 status = -1; 435 } 436 else if (!is_stdio) 437 { 438 if (close(fd) < 0) 439 status = -1; 440 } 441 442 return (status); 443} 444 445 446/* 447 * 'cupsFileCompression()' - Return whether a file is compressed. 448 * 449 * @since CUPS 1.2/OS X 10.5@ 450 */ 451 452int /* O - @code CUPS_FILE_NONE@ or @code CUPS_FILE_GZIP@ */ 453cupsFileCompression(cups_file_t *fp) /* I - CUPS file */ 454{ 455 return (fp ? fp->compressed : CUPS_FILE_NONE); 456} 457 458 459/* 460 * 'cupsFileEOF()' - Return the end-of-file status. 461 * 462 * @since CUPS 1.2/OS X 10.5@ 463 */ 464 465int /* O - 1 on end of file, 0 otherwise */ 466cupsFileEOF(cups_file_t *fp) /* I - CUPS file */ 467{ 468 return (fp ? fp->eof : 1); 469} 470 471 472/* 473 * 'cupsFileFind()' - Find a file using the specified path. 474 * 475 * This function allows the paths in the path string to be separated by 476 * colons (UNIX standard) or semicolons (Windows standard) and stores the 477 * result in the buffer supplied. If the file cannot be found in any of 478 * the supplied paths, @code NULL@ is returned. A @code NULL@ path only 479 * matches the current directory. 480 * 481 * @since CUPS 1.2/OS X 10.5@ 482 */ 483 484const char * /* O - Full path to file or @code NULL@ if not found */ 485cupsFileFind(const char *filename, /* I - File to find */ 486 const char *path, /* I - Colon/semicolon-separated path */ 487 int executable, /* I - 1 = executable files, 0 = any file/dir */ 488 char *buffer, /* I - Filename buffer */ 489 int bufsize) /* I - Size of filename buffer */ 490{ 491 char *bufptr, /* Current position in buffer */ 492 *bufend; /* End of buffer */ 493 494 495 /* 496 * Range check input... 497 */ 498 499 DEBUG_printf(("cupsFileFind(filename=\"%s\", path=\"%s\", executable=%d, " 500 "buffer=%p, bufsize=%d)", filename, path, executable, buffer, 501 bufsize)); 502 503 if (!filename || !buffer || bufsize < 2) 504 return (NULL); 505 506 if (!path) 507 { 508 /* 509 * No path, so check current directory... 510 */ 511 512 if (!access(filename, 0)) 513 { 514 strlcpy(buffer, filename, bufsize); 515 return (buffer); 516 } 517 else 518 return (NULL); 519 } 520 521 /* 522 * Now check each path and return the first match... 523 */ 524 525 bufend = buffer + bufsize - 1; 526 bufptr = buffer; 527 528 while (*path) 529 { 530#ifdef WIN32 531 if (*path == ';' || (*path == ':' && ((bufptr - buffer) > 1 || !isalpha(buffer[0] & 255)))) 532#else 533 if (*path == ';' || *path == ':') 534#endif /* WIN32 */ 535 { 536 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend) 537 *bufptr++ = '/'; 538 539 strlcpy(bufptr, filename, bufend - bufptr); 540 541#ifdef WIN32 542 if (!access(buffer, 0)) 543#else 544 if (!access(buffer, executable ? X_OK : 0)) 545#endif /* WIN32 */ 546 { 547 DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer)); 548 return (buffer); 549 } 550 551 bufptr = buffer; 552 } 553 else if (bufptr < bufend) 554 *bufptr++ = *path; 555 556 path ++; 557 } 558 559 /* 560 * Check the last path... 561 */ 562 563 if (bufptr > buffer && bufptr[-1] != '/' && bufptr < bufend) 564 *bufptr++ = '/'; 565 566 strlcpy(bufptr, filename, bufend - bufptr); 567 568 if (!access(buffer, 0)) 569 { 570 DEBUG_printf(("1cupsFileFind: Returning \"%s\"", buffer)); 571 return (buffer); 572 } 573 else 574 { 575 DEBUG_puts("1cupsFileFind: Returning NULL"); 576 return (NULL); 577 } 578} 579 580 581/* 582 * 'cupsFileFlush()' - Flush pending output. 583 * 584 * @since CUPS 1.2/OS X 10.5@ 585 */ 586 587int /* O - 0 on success, -1 on error */ 588cupsFileFlush(cups_file_t *fp) /* I - CUPS file */ 589{ 590 ssize_t bytes; /* Bytes to write */ 591 592 593 DEBUG_printf(("cupsFileFlush(fp=%p)", fp)); 594 595 /* 596 * Range check input... 597 */ 598 599 if (!fp || fp->mode != 'w') 600 { 601 DEBUG_puts("1cupsFileFlush: Attempt to flush a read-only file..."); 602 return (-1); 603 } 604 605 bytes = (ssize_t)(fp->ptr - fp->buf); 606 607 DEBUG_printf(("2cupsFileFlush: Flushing " CUPS_LLFMT " bytes...", 608 CUPS_LLCAST bytes)); 609 610 if (bytes > 0) 611 { 612#ifdef HAVE_LIBZ 613 if (fp->compressed) 614 bytes = cups_compress(fp, fp->buf, bytes); 615 else 616#endif /* HAVE_LIBZ */ 617 bytes = cups_write(fp, fp->buf, bytes); 618 619 if (bytes < 0) 620 return (-1); 621 622 fp->ptr = fp->buf; 623 } 624 625 return (0); 626} 627 628 629/* 630 * 'cupsFileGetChar()' - Get a single character from a file. 631 * 632 * @since CUPS 1.2/OS X 10.5@ 633 */ 634 635int /* O - Character or -1 on end of file */ 636cupsFileGetChar(cups_file_t *fp) /* I - CUPS file */ 637{ 638 /* 639 * Range check input... 640 */ 641 642 if (!fp || (fp->mode != 'r' && fp->mode != 's')) 643 { 644 DEBUG_puts("5cupsFileGetChar: Bad arguments!"); 645 return (-1); 646 } 647 648 /* 649 * If the input buffer is empty, try to read more data... 650 */ 651 652 if (fp->ptr >= fp->end) 653 if (cups_fill(fp) < 0) 654 { 655 DEBUG_puts("5cupsFileGetChar: Unable to fill buffer!"); 656 return (-1); 657 } 658 659 /* 660 * Return the next character in the buffer... 661 */ 662 663 DEBUG_printf(("5cupsFileGetChar: Returning %d...", *(fp->ptr) & 255)); 664 665 fp->pos ++; 666 667 DEBUG_printf(("6cupsFileGetChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 668 669 return (*(fp->ptr)++ & 255); 670} 671 672 673/* 674 * 'cupsFileGetConf()' - Get a line from a configuration file. 675 * 676 * @since CUPS 1.2/OS X 10.5@ 677 */ 678 679char * /* O - Line read or @code NULL@ on end of file or error */ 680cupsFileGetConf(cups_file_t *fp, /* I - CUPS file */ 681 char *buf, /* O - String buffer */ 682 size_t buflen, /* I - Size of string buffer */ 683 char **value, /* O - Pointer to value */ 684 int *linenum) /* IO - Current line number */ 685{ 686 char *ptr; /* Pointer into line */ 687 688 689 /* 690 * Range check input... 691 */ 692 693 DEBUG_printf(("2cupsFileGetConf(fp=%p, buf=%p, buflen=" CUPS_LLFMT 694 ", value=%p, linenum=%p)", fp, buf, CUPS_LLCAST buflen, 695 value, linenum)); 696 697 if (!fp || (fp->mode != 'r' && fp->mode != 's') || 698 !buf || buflen < 2 || !value) 699 { 700 if (value) 701 *value = NULL; 702 703 return (NULL); 704 } 705 706 /* 707 * Read the next non-comment line... 708 */ 709 710 *value = NULL; 711 712 while (cupsFileGets(fp, buf, buflen)) 713 { 714 (*linenum) ++; 715 716 /* 717 * Strip any comments... 718 */ 719 720 if ((ptr = strchr(buf, '#')) != NULL) 721 { 722 if (ptr > buf && ptr[-1] == '\\') 723 { 724 // Unquote the #... 725 _cups_strcpy(ptr - 1, ptr); 726 } 727 else 728 { 729 // Strip the comment and any trailing whitespace... 730 while (ptr > buf) 731 { 732 if (!_cups_isspace(ptr[-1])) 733 break; 734 735 ptr --; 736 } 737 738 *ptr = '\0'; 739 } 740 } 741 742 /* 743 * Strip leading whitespace... 744 */ 745 746 for (ptr = buf; _cups_isspace(*ptr); ptr ++); 747 748 if (ptr > buf) 749 _cups_strcpy(buf, ptr); 750 751 /* 752 * See if there is anything left... 753 */ 754 755 if (buf[0]) 756 { 757 /* 758 * Yes, grab any value and return... 759 */ 760 761 for (ptr = buf; *ptr; ptr ++) 762 if (_cups_isspace(*ptr)) 763 break; 764 765 if (*ptr) 766 { 767 /* 768 * Have a value, skip any other spaces... 769 */ 770 771 while (_cups_isspace(*ptr)) 772 *ptr++ = '\0'; 773 774 if (*ptr) 775 *value = ptr; 776 777 /* 778 * Strip trailing whitespace and > for lines that begin with <... 779 */ 780 781 ptr += strlen(ptr) - 1; 782 783 if (buf[0] == '<' && *ptr == '>') 784 *ptr-- = '\0'; 785 else if (buf[0] == '<' && *ptr != '>') 786 { 787 /* 788 * Syntax error... 789 */ 790 791 *value = NULL; 792 return (buf); 793 } 794 795 while (ptr > *value && _cups_isspace(*ptr)) 796 *ptr-- = '\0'; 797 } 798 799 /* 800 * Return the line... 801 */ 802 803 return (buf); 804 } 805 } 806 807 return (NULL); 808} 809 810 811/* 812 * 'cupsFileGetLine()' - Get a CR and/or LF-terminated line that may 813 * contain binary data. 814 * 815 * This function differs from @link cupsFileGets@ in that the trailing CR 816 * and LF are preserved, as is any binary data on the line. The buffer is 817 * nul-terminated, however you should use the returned length to determine 818 * the number of bytes on the line. 819 * 820 * @since CUPS 1.2/OS X 10.5@ 821 */ 822 823size_t /* O - Number of bytes on line or 0 on end of file */ 824cupsFileGetLine(cups_file_t *fp, /* I - File to read from */ 825 char *buf, /* I - Buffer */ 826 size_t buflen) /* I - Size of buffer */ 827{ 828 int ch; /* Character from file */ 829 char *ptr, /* Current position in line buffer */ 830 *end; /* End of line buffer */ 831 832 833 /* 834 * Range check input... 835 */ 836 837 DEBUG_printf(("2cupsFileGetLine(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", 838 fp, buf, CUPS_LLCAST buflen)); 839 840 if (!fp || (fp->mode != 'r' && fp->mode != 's') || !buf || buflen < 3) 841 return (0); 842 843 /* 844 * Now loop until we have a valid line... 845 */ 846 847 for (ptr = buf, end = buf + buflen - 2; ptr < end ;) 848 { 849 if (fp->ptr >= fp->end) 850 if (cups_fill(fp) <= 0) 851 break; 852 853 *ptr++ = ch = *(fp->ptr)++; 854 fp->pos ++; 855 856 if (ch == '\r') 857 { 858 /* 859 * Check for CR LF... 860 */ 861 862 if (fp->ptr >= fp->end) 863 if (cups_fill(fp) <= 0) 864 break; 865 866 if (*(fp->ptr) == '\n') 867 { 868 *ptr++ = *(fp->ptr)++; 869 fp->pos ++; 870 } 871 872 break; 873 } 874 else if (ch == '\n') 875 { 876 /* 877 * Line feed ends a line... 878 */ 879 880 break; 881 } 882 } 883 884 *ptr = '\0'; 885 886 DEBUG_printf(("4cupsFileGetLine: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 887 888 return (ptr - buf); 889} 890 891 892/* 893 * 'cupsFileGets()' - Get a CR and/or LF-terminated line. 894 * 895 * @since CUPS 1.2/OS X 10.5@ 896 */ 897 898char * /* O - Line read or @code NULL@ on end of file or error */ 899cupsFileGets(cups_file_t *fp, /* I - CUPS file */ 900 char *buf, /* O - String buffer */ 901 size_t buflen) /* I - Size of string buffer */ 902{ 903 int ch; /* Character from file */ 904 char *ptr, /* Current position in line buffer */ 905 *end; /* End of line buffer */ 906 907 908 /* 909 * Range check input... 910 */ 911 912 DEBUG_printf(("2cupsFileGets(fp=%p, buf=%p, buflen=" CUPS_LLFMT ")", fp, buf, 913 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++ = 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/OS X 10.5@ 978 */ 979 980int /* O - 0 on success, -1 on error */ 981cupsFileLock(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/OS X 10.5@ 1007 */ 1008 1009int /* O - File descriptor */ 1010cupsFileNumber(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/OS X 10.5@ 1036 */ 1037 1038cups_file_t * /* O - CUPS file or @code NULL@ if the file or socket cannot be opened */ 1039cupsFileOpen(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 closesocket(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/OS X 10.5@ 1158 */ 1159 1160cups_file_t * /* O - CUPS file or @code NULL@ if the file could not be opened */ 1161cupsFileOpenFd(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] = curtime; 1219 header[5] = curtime >> 8; 1220 header[6] = curtime >> 16; 1221 header[7] = 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/OS X 10.5@ 1270 */ 1271 1272int /* O - Character or -1 on end of file */ 1273cupsFilePeekChar(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/OS X 10.5@ 1302 */ 1303 1304int /* O - Number of bytes written or -1 on error */ 1305cupsFilePrintf(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\", ...)", 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, bytes + 1)) == NULL) 1347 return (-1); 1348 1349 fp->printf_buffer = temp; 1350 fp->printf_size = 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, 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 (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 (bytes > sizeof(fp->buf)) 1378 { 1379#ifdef HAVE_LIBZ 1380 if (fp->compressed) 1381 return (cups_compress(fp, fp->printf_buffer, bytes)); 1382 else 1383#endif /* HAVE_LIBZ */ 1384 return (cups_write(fp, fp->printf_buffer, bytes)); 1385 } 1386 else 1387 { 1388 memcpy(fp->ptr, fp->printf_buffer, bytes); 1389 fp->ptr += bytes; 1390 return (bytes); 1391 } 1392} 1393 1394 1395/* 1396 * 'cupsFilePutChar()' - Write a character. 1397 * 1398 * @since CUPS 1.2/OS X 10.5@ 1399 */ 1400 1401int /* O - 0 on success, -1 on error */ 1402cupsFilePutChar(cups_file_t *fp, /* I - CUPS file */ 1403 int c) /* I - Character to write */ 1404{ 1405 /* 1406 * Range check input... 1407 */ 1408 1409 if (!fp || (fp->mode != 'w' && fp->mode != 's')) 1410 return (-1); 1411 1412 if (fp->mode == 's') 1413 { 1414 /* 1415 * Send character immediately over socket... 1416 */ 1417 1418 char ch; /* Output character */ 1419 1420 1421 ch = c; 1422 1423 if (send(fp->fd, &ch, 1, 0) < 1) 1424 return (-1); 1425 } 1426 else 1427 { 1428 /* 1429 * Buffer it up... 1430 */ 1431 1432 if (fp->ptr >= fp->end) 1433 if (cupsFileFlush(fp)) 1434 return (-1); 1435 1436 *(fp->ptr) ++ = c; 1437 } 1438 1439 fp->pos ++; 1440 1441 DEBUG_printf(("4cupsFilePutChar: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1442 1443 return (0); 1444} 1445 1446 1447/* 1448 * 'cupsFilePutConf()' - Write a configuration line. 1449 * 1450 * This function handles any comment escaping of the value. 1451 * 1452 * @since CUPS 1.4/OS X 10.6@ 1453 */ 1454 1455ssize_t /* O - Number of bytes written or -1 on error */ 1456cupsFilePutConf(cups_file_t *fp, /* I - CUPS file */ 1457 const char *directive, /* I - Directive */ 1458 const char *value) /* I - Value */ 1459{ 1460 ssize_t bytes, /* Number of bytes written */ 1461 temp; /* Temporary byte count */ 1462 const char *ptr; /* Pointer into value */ 1463 1464 1465 if (!fp || !directive || !*directive) 1466 return (-1); 1467 1468 if ((bytes = cupsFilePuts(fp, directive)) < 0) 1469 return (-1); 1470 1471 if (cupsFilePutChar(fp, ' ') < 0) 1472 return (-1); 1473 bytes ++; 1474 1475 if (value && *value) 1476 { 1477 if ((ptr = strchr(value, '#')) != NULL) 1478 { 1479 /* 1480 * Need to quote the first # in the info string... 1481 */ 1482 1483 if ((temp = cupsFileWrite(fp, value, ptr - value)) < 0) 1484 return (-1); 1485 bytes += temp; 1486 1487 if (cupsFilePutChar(fp, '\\') < 0) 1488 return (-1); 1489 bytes ++; 1490 1491 if ((temp = cupsFilePuts(fp, ptr)) < 0) 1492 return (-1); 1493 bytes += temp; 1494 } 1495 else if ((temp = cupsFilePuts(fp, value)) < 0) 1496 return (-1); 1497 else 1498 bytes += temp; 1499 } 1500 1501 if (cupsFilePutChar(fp, '\n') < 0) 1502 return (-1); 1503 else 1504 return (bytes + 1); 1505} 1506 1507 1508/* 1509 * 'cupsFilePuts()' - Write a string. 1510 * 1511 * Like the @code fputs@ function, no newline is appended to the string. 1512 * 1513 * @since CUPS 1.2/OS X 10.5@ 1514 */ 1515 1516int /* O - Number of bytes written or -1 on error */ 1517cupsFilePuts(cups_file_t *fp, /* I - CUPS file */ 1518 const char *s) /* I - String to write */ 1519{ 1520 ssize_t bytes; /* Bytes to write */ 1521 1522 1523 /* 1524 * Range check input... 1525 */ 1526 1527 if (!fp || !s || (fp->mode != 'w' && fp->mode != 's')) 1528 return (-1); 1529 1530 /* 1531 * Write the string... 1532 */ 1533 1534 bytes = (int)strlen(s); 1535 1536 if (fp->mode == 's') 1537 { 1538 if (cups_write(fp, s, bytes) < 0) 1539 return (-1); 1540 1541 fp->pos += bytes; 1542 1543 DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1544 1545 return (bytes); 1546 } 1547 1548 if ((fp->ptr + bytes) > fp->end) 1549 if (cupsFileFlush(fp)) 1550 return (-1); 1551 1552 fp->pos += bytes; 1553 1554 DEBUG_printf(("4cupsFilePuts: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1555 1556 if (bytes > sizeof(fp->buf)) 1557 { 1558#ifdef HAVE_LIBZ 1559 if (fp->compressed) 1560 return (cups_compress(fp, s, bytes)); 1561 else 1562#endif /* HAVE_LIBZ */ 1563 return (cups_write(fp, s, bytes)); 1564 } 1565 else 1566 { 1567 memcpy(fp->ptr, s, bytes); 1568 fp->ptr += bytes; 1569 return (bytes); 1570 } 1571} 1572 1573 1574/* 1575 * 'cupsFileRead()' - Read from a file. 1576 * 1577 * @since CUPS 1.2/OS X 10.5@ 1578 */ 1579 1580ssize_t /* O - Number of bytes read or -1 on error */ 1581cupsFileRead(cups_file_t *fp, /* I - CUPS file */ 1582 char *buf, /* O - Buffer */ 1583 size_t bytes) /* I - Number of bytes to read */ 1584{ 1585 size_t total; /* Total bytes read */ 1586 ssize_t count; /* Bytes read */ 1587 1588 1589 DEBUG_printf(("2cupsFileRead(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf, 1590 CUPS_LLCAST bytes)); 1591 1592 /* 1593 * Range check input... 1594 */ 1595 1596 if (!fp || !buf || (fp->mode != 'r' && fp->mode != 's')) 1597 return (-1); 1598 1599 if (bytes == 0) 1600 return (0); 1601 1602 /* 1603 * Loop until all bytes are read... 1604 */ 1605 1606 total = 0; 1607 while (bytes > 0) 1608 { 1609 if (fp->ptr >= fp->end) 1610 if (cups_fill(fp) <= 0) 1611 { 1612 DEBUG_printf(("4cupsFileRead: cups_fill() returned -1, total=" 1613 CUPS_LLFMT, CUPS_LLCAST total)); 1614 1615 if (total > 0) 1616 return ((ssize_t)total); 1617 else 1618 return (-1); 1619 } 1620 1621 count = (ssize_t)(fp->end - fp->ptr); 1622 if (count > (ssize_t)bytes) 1623 count = (ssize_t)bytes; 1624 1625 memcpy(buf, fp->ptr, count); 1626 fp->ptr += count; 1627 fp->pos += count; 1628 1629 DEBUG_printf(("4cupsFileRead: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1630 1631 /* 1632 * Update the counts for the last read... 1633 */ 1634 1635 bytes -= count; 1636 total += count; 1637 buf += count; 1638 } 1639 1640 /* 1641 * Return the total number of bytes read... 1642 */ 1643 1644 DEBUG_printf(("3cupsFileRead: total=" CUPS_LLFMT, CUPS_LLCAST total)); 1645 1646 return ((ssize_t)total); 1647} 1648 1649 1650/* 1651 * 'cupsFileRewind()' - Set the current file position to the beginning of the 1652 * file. 1653 * 1654 * @since CUPS 1.2/OS X 10.5@ 1655 */ 1656 1657off_t /* O - New file position or -1 on error */ 1658cupsFileRewind(cups_file_t *fp) /* I - CUPS file */ 1659{ 1660 /* 1661 * Range check input... 1662 */ 1663 1664 DEBUG_printf(("cupsFileRewind(fp=%p)", fp)); 1665 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1666 1667 if (!fp || fp->mode != 'r') 1668 return (-1); 1669 1670 /* 1671 * Handle special cases... 1672 */ 1673 1674 if (fp->bufpos == 0) 1675 { 1676 /* 1677 * No seeking necessary... 1678 */ 1679 1680 fp->pos = 0; 1681 1682 if (fp->ptr) 1683 { 1684 fp->ptr = fp->buf; 1685 fp->eof = 0; 1686 } 1687 1688 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1689 1690 return (0); 1691 } 1692 1693 /* 1694 * Otherwise, seek in the file and cleanup any compression buffers... 1695 */ 1696 1697#ifdef HAVE_LIBZ 1698 if (fp->compressed) 1699 { 1700 inflateEnd(&fp->stream); 1701 fp->compressed = 0; 1702 } 1703#endif /* HAVE_LIBZ */ 1704 1705 if (lseek(fp->fd, 0, SEEK_SET)) 1706 { 1707 DEBUG_printf(("1cupsFileRewind: lseek failed: %s", strerror(errno))); 1708 return (-1); 1709 } 1710 1711 fp->bufpos = 0; 1712 fp->pos = 0; 1713 fp->ptr = NULL; 1714 fp->end = NULL; 1715 fp->eof = 0; 1716 1717 DEBUG_printf(("2cupsFileRewind: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1718 1719 return (0); 1720} 1721 1722 1723/* 1724 * 'cupsFileSeek()' - Seek in a file. 1725 * 1726 * @since CUPS 1.2/OS X 10.5@ 1727 */ 1728 1729off_t /* O - New file position or -1 on error */ 1730cupsFileSeek(cups_file_t *fp, /* I - CUPS file */ 1731 off_t pos) /* I - Position in file */ 1732{ 1733 ssize_t bytes; /* Number bytes in buffer */ 1734 1735 1736 DEBUG_printf(("cupsFileSeek(fp=%p, pos=" CUPS_LLFMT ")", fp, 1737 CUPS_LLCAST pos)); 1738 DEBUG_printf(("2cupsFileSeek: fp->pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1739 DEBUG_printf(("2cupsFileSeek: fp->ptr=%p, fp->end=%p", fp->ptr, fp->end)); 1740 1741 /* 1742 * Range check input... 1743 */ 1744 1745 if (!fp || pos < 0 || fp->mode != 'r') 1746 return (-1); 1747 1748 /* 1749 * Handle special cases... 1750 */ 1751 1752 if (pos == 0) 1753 return (cupsFileRewind(fp)); 1754 1755 if (fp->ptr) 1756 { 1757 bytes = (ssize_t)(fp->end - fp->buf); 1758 1759 DEBUG_printf(("2cupsFileSeek: bytes=" CUPS_LLFMT, CUPS_LLCAST bytes)); 1760 1761 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) 1762 { 1763 /* 1764 * No seeking necessary... 1765 */ 1766 1767 fp->pos = pos; 1768 fp->ptr = fp->buf + pos - fp->bufpos; 1769 fp->eof = 0; 1770 1771 return (pos); 1772 } 1773 } 1774 1775#ifdef HAVE_LIBZ 1776 if (!fp->compressed && !fp->ptr) 1777 { 1778 /* 1779 * Preload a buffer to determine whether the file is compressed... 1780 */ 1781 1782 if (cups_fill(fp) < 0) 1783 return (-1); 1784 } 1785#endif /* HAVE_LIBZ */ 1786 1787 /* 1788 * Seek forwards or backwards... 1789 */ 1790 1791 fp->eof = 0; 1792 1793 if (pos < fp->bufpos) 1794 { 1795 /* 1796 * Need to seek backwards... 1797 */ 1798 1799 DEBUG_puts("2cupsFileSeek: SEEK BACKWARDS"); 1800 1801#ifdef HAVE_LIBZ 1802 if (fp->compressed) 1803 { 1804 inflateEnd(&fp->stream); 1805 1806 lseek(fp->fd, 0, SEEK_SET); 1807 fp->bufpos = 0; 1808 fp->pos = 0; 1809 fp->ptr = NULL; 1810 fp->end = NULL; 1811 1812 while ((bytes = cups_fill(fp)) > 0) 1813 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) 1814 break; 1815 1816 if (bytes <= 0) 1817 return (-1); 1818 1819 fp->ptr = fp->buf + pos - fp->bufpos; 1820 fp->pos = pos; 1821 } 1822 else 1823#endif /* HAVE_LIBZ */ 1824 { 1825 fp->bufpos = lseek(fp->fd, pos, SEEK_SET); 1826 fp->pos = fp->bufpos; 1827 fp->ptr = NULL; 1828 fp->end = NULL; 1829 1830 DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT, 1831 CUPS_LLCAST fp->pos)); 1832 } 1833 } 1834 else 1835 { 1836 /* 1837 * Need to seek forwards... 1838 */ 1839 1840 DEBUG_puts("2cupsFileSeek: SEEK FORWARDS"); 1841 1842#ifdef HAVE_LIBZ 1843 if (fp->compressed) 1844 { 1845 while ((bytes = cups_fill(fp)) > 0) 1846 { 1847 if (pos >= fp->bufpos && pos < (fp->bufpos + bytes)) 1848 break; 1849 } 1850 1851 if (bytes <= 0) 1852 return (-1); 1853 1854 fp->ptr = fp->buf + pos - fp->bufpos; 1855 fp->pos = pos; 1856 } 1857 else 1858#endif /* HAVE_LIBZ */ 1859 { 1860 fp->bufpos = lseek(fp->fd, pos, SEEK_SET); 1861 fp->pos = fp->bufpos; 1862 fp->ptr = NULL; 1863 fp->end = NULL; 1864 1865 DEBUG_printf(("2cupsFileSeek: lseek() returned " CUPS_LLFMT, 1866 CUPS_LLCAST fp->pos)); 1867 } 1868 } 1869 1870 DEBUG_printf(("2cupsFileSeek: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 1871 1872 return (fp->pos); 1873} 1874 1875 1876/* 1877 * 'cupsFileStderr()' - Return a CUPS file associated with stderr. 1878 * 1879 * @since CUPS 1.2/OS X 10.5@ 1880 */ 1881 1882cups_file_t * /* O - CUPS file */ 1883cupsFileStderr(void) 1884{ 1885 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ 1886 1887 1888 /* 1889 * Open file descriptor 2 as needed... 1890 */ 1891 1892 if (!cg->stdio_files[2]) 1893 { 1894 /* 1895 * Flush any pending output on the stdio file... 1896 */ 1897 1898 fflush(stderr); 1899 1900 /* 1901 * Open file descriptor 2... 1902 */ 1903 1904 if ((cg->stdio_files[2] = cupsFileOpenFd(2, "w")) != NULL) 1905 cg->stdio_files[2]->is_stdio = 1; 1906 } 1907 1908 return (cg->stdio_files[2]); 1909} 1910 1911 1912/* 1913 * 'cupsFileStdin()' - Return a CUPS file associated with stdin. 1914 * 1915 * @since CUPS 1.2/OS X 10.5@ 1916 */ 1917 1918cups_file_t * /* O - CUPS file */ 1919cupsFileStdin(void) 1920{ 1921 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ 1922 1923 1924 /* 1925 * Open file descriptor 0 as needed... 1926 */ 1927 1928 if (!cg->stdio_files[0]) 1929 { 1930 /* 1931 * Open file descriptor 0... 1932 */ 1933 1934 if ((cg->stdio_files[0] = cupsFileOpenFd(0, "r")) != NULL) 1935 cg->stdio_files[0]->is_stdio = 1; 1936 } 1937 1938 return (cg->stdio_files[0]); 1939} 1940 1941 1942/* 1943 * 'cupsFileStdout()' - Return a CUPS file associated with stdout. 1944 * 1945 * @since CUPS 1.2/OS X 10.5@ 1946 */ 1947 1948cups_file_t * /* O - CUPS file */ 1949cupsFileStdout(void) 1950{ 1951 _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals... */ 1952 1953 1954 /* 1955 * Open file descriptor 1 as needed... 1956 */ 1957 1958 if (!cg->stdio_files[1]) 1959 { 1960 /* 1961 * Flush any pending output on the stdio file... 1962 */ 1963 1964 fflush(stdout); 1965 1966 /* 1967 * Open file descriptor 1... 1968 */ 1969 1970 if ((cg->stdio_files[1] = cupsFileOpenFd(1, "w")) != NULL) 1971 cg->stdio_files[1]->is_stdio = 1; 1972 } 1973 1974 return (cg->stdio_files[1]); 1975} 1976 1977 1978/* 1979 * 'cupsFileTell()' - Return the current file position. 1980 * 1981 * @since CUPS 1.2/OS X 10.5@ 1982 */ 1983 1984off_t /* O - File position */ 1985cupsFileTell(cups_file_t *fp) /* I - CUPS file */ 1986{ 1987 DEBUG_printf(("2cupsFileTell(fp=%p)", fp)); 1988 DEBUG_printf(("3cupsFileTell: pos=" CUPS_LLFMT, 1989 CUPS_LLCAST (fp ? fp->pos : -1))); 1990 1991 return (fp ? fp->pos : 0); 1992} 1993 1994 1995/* 1996 * 'cupsFileUnlock()' - Unlock access to a file. 1997 * 1998 * @since CUPS 1.2/OS X 10.5@ 1999 */ 2000 2001int /* O - 0 on success, -1 on error */ 2002cupsFileUnlock(cups_file_t *fp) /* I - CUPS file */ 2003{ 2004 /* 2005 * Range check... 2006 */ 2007 2008 DEBUG_printf(("cupsFileUnlock(fp=%p)", fp)); 2009 2010 if (!fp || fp->mode == 's') 2011 return (-1); 2012 2013 /* 2014 * Unlock... 2015 */ 2016 2017#ifdef WIN32 2018 return (_locking(fp->fd, _LK_UNLCK, 0)); 2019#else 2020 return (lockf(fp->fd, F_ULOCK, 0)); 2021#endif /* WIN32 */ 2022} 2023 2024 2025/* 2026 * 'cupsFileWrite()' - Write to a file. 2027 * 2028 * @since CUPS 1.2/OS X 10.5@ 2029 */ 2030 2031ssize_t /* O - Number of bytes written or -1 on error */ 2032cupsFileWrite(cups_file_t *fp, /* I - CUPS file */ 2033 const char *buf, /* I - Buffer */ 2034 size_t bytes) /* I - Number of bytes to write */ 2035{ 2036 /* 2037 * Range check input... 2038 */ 2039 2040 DEBUG_printf(("2cupsFileWrite(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", 2041 fp, buf, CUPS_LLCAST bytes)); 2042 2043 if (!fp || !buf || (fp->mode != 'w' && fp->mode != 's')) 2044 return (-1); 2045 2046 if (bytes == 0) 2047 return (0); 2048 2049 /* 2050 * Write the buffer... 2051 */ 2052 2053 if (fp->mode == 's') 2054 { 2055 if (cups_write(fp, buf, bytes) < 0) 2056 return (-1); 2057 2058 fp->pos += (off_t)bytes; 2059 2060 DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 2061 2062 return ((ssize_t)bytes); 2063 } 2064 2065 if ((fp->ptr + bytes) > fp->end) 2066 if (cupsFileFlush(fp)) 2067 return (-1); 2068 2069 fp->pos += (off_t)bytes; 2070 2071 DEBUG_printf(("4cupsFileWrite: pos=" CUPS_LLFMT, CUPS_LLCAST fp->pos)); 2072 2073 if (bytes > sizeof(fp->buf)) 2074 { 2075#ifdef HAVE_LIBZ 2076 if (fp->compressed) 2077 return (cups_compress(fp, buf, bytes)); 2078 else 2079#endif /* HAVE_LIBZ */ 2080 return (cups_write(fp, buf, bytes)); 2081 } 2082 else 2083 { 2084 memcpy(fp->ptr, buf, bytes); 2085 fp->ptr += bytes; 2086 return ((ssize_t)bytes); 2087 } 2088} 2089 2090 2091#ifdef HAVE_LIBZ 2092/* 2093 * 'cups_compress()' - Compress a buffer of data. 2094 */ 2095 2096static ssize_t /* O - Number of bytes written or -1 */ 2097cups_compress(cups_file_t *fp, /* I - CUPS file */ 2098 const char *buf, /* I - Buffer */ 2099 size_t bytes) /* I - Number bytes */ 2100{ 2101 DEBUG_printf(("7cups_compress(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf, 2102 CUPS_LLCAST bytes)); 2103 2104 /* 2105 * Update the CRC... 2106 */ 2107 2108 fp->crc = crc32(fp->crc, (const Bytef *)buf, bytes); 2109 2110 /* 2111 * Deflate the bytes... 2112 */ 2113 2114 fp->stream.next_in = (Bytef *)buf; 2115 fp->stream.avail_in = bytes; 2116 2117 while (fp->stream.avail_in > 0) 2118 { 2119 /* 2120 * Flush the current buffer... 2121 */ 2122 2123 DEBUG_printf(("9cups_compress: avail_in=%d, avail_out=%d", 2124 fp->stream.avail_in, fp->stream.avail_out)); 2125 2126 if (fp->stream.avail_out < (int)(sizeof(fp->cbuf) / 8)) 2127 { 2128 if (cups_write(fp, (char *)fp->cbuf, fp->stream.next_out - fp->cbuf) < 0) 2129 return (-1); 2130 2131 fp->stream.next_out = fp->cbuf; 2132 fp->stream.avail_out = sizeof(fp->cbuf); 2133 } 2134 2135 deflate(&(fp->stream), Z_NO_FLUSH); 2136 } 2137 2138 return (bytes); 2139} 2140#endif /* HAVE_LIBZ */ 2141 2142 2143/* 2144 * 'cups_fill()' - Fill the input buffer. 2145 */ 2146 2147static ssize_t /* O - Number of bytes or -1 */ 2148cups_fill(cups_file_t *fp) /* I - CUPS file */ 2149{ 2150 ssize_t bytes; /* Number of bytes read */ 2151#ifdef HAVE_LIBZ 2152 int status; /* Decompression status */ 2153 const unsigned char *ptr, /* Pointer into buffer */ 2154 *end; /* End of buffer */ 2155#endif /* HAVE_LIBZ */ 2156 2157 2158 DEBUG_printf(("7cups_fill(fp=%p)", fp)); 2159 DEBUG_printf(("9cups_fill: fp->ptr=%p, fp->end=%p, fp->buf=%p, " 2160 "fp->bufpos=" CUPS_LLFMT ", fp->eof=%d", 2161 fp->ptr, fp->end, fp->buf, CUPS_LLCAST fp->bufpos, fp->eof)); 2162 2163 if (fp->ptr && fp->end) 2164 fp->bufpos += fp->end - fp->buf; 2165 2166#ifdef HAVE_LIBZ 2167 DEBUG_printf(("9cups_fill: fp->compressed=%d", fp->compressed)); 2168 2169 while (!fp->ptr || fp->compressed) 2170 { 2171 /* 2172 * Check to see if we have read any data yet; if not, see if we have a 2173 * compressed file... 2174 */ 2175 2176 if (!fp->ptr) 2177 { 2178 /* 2179 * Reset the file position in case we are seeking... 2180 */ 2181 2182 fp->compressed = 0; 2183 2184 /* 2185 * Read the first bytes in the file to determine if we have a gzip'd 2186 * file... 2187 */ 2188 2189 if ((bytes = cups_read(fp, (char *)fp->buf, sizeof(fp->buf))) < 0) 2190 { 2191 /* 2192 * Can't read from file! 2193 */ 2194 2195 DEBUG_printf(("9cups_fill: cups_read() returned " CUPS_LLFMT, 2196 CUPS_LLCAST bytes)); 2197 2198 return (-1); 2199 } 2200 2201 if (bytes < 10 || fp->buf[0] != 0x1f || 2202 (fp->buf[1] & 255) != 0x8b || 2203 fp->buf[2] != 8 || (fp->buf[3] & 0xe0) != 0) 2204 { 2205 /* 2206 * Not a gzip'd file! 2207 */ 2208 2209 fp->ptr = fp->buf; 2210 fp->end = fp->buf + bytes; 2211 2212 DEBUG_printf(("9cups_fill: Returning " CUPS_LLFMT, 2213 CUPS_LLCAST bytes)); 2214 2215 return (bytes); 2216 } 2217 2218 /* 2219 * Parse header junk: extra data, original name, and comment... 2220 */ 2221 2222 ptr = (unsigned char *)fp->buf + 10; 2223 end = (unsigned char *)fp->buf + bytes; 2224 2225 if (fp->buf[3] & 0x04) 2226 { 2227 /* 2228 * Skip extra data... 2229 */ 2230 2231 if ((ptr + 2) > end) 2232 { 2233 /* 2234 * Can't read from file! 2235 */ 2236 2237 return (-1); 2238 } 2239 2240 bytes = ((unsigned char)ptr[1] << 8) | (unsigned char)ptr[0]; 2241 ptr += 2 + bytes; 2242 2243 if (ptr > end) 2244 { 2245 /* 2246 * Can't read from file! 2247 */ 2248 2249 return (-1); 2250 } 2251 } 2252 2253 if (fp->buf[3] & 0x08) 2254 { 2255 /* 2256 * Skip original name data... 2257 */ 2258 2259 while (ptr < end && *ptr) 2260 ptr ++; 2261 2262 if (ptr < end) 2263 ptr ++; 2264 else 2265 { 2266 /* 2267 * Can't read from file! 2268 */ 2269 2270 return (-1); 2271 } 2272 } 2273 2274 if (fp->buf[3] & 0x10) 2275 { 2276 /* 2277 * Skip comment data... 2278 */ 2279 2280 while (ptr < end && *ptr) 2281 ptr ++; 2282 2283 if (ptr < end) 2284 ptr ++; 2285 else 2286 { 2287 /* 2288 * Can't read from file! 2289 */ 2290 2291 return (-1); 2292 } 2293 } 2294 2295 if (fp->buf[3] & 0x02) 2296 { 2297 /* 2298 * Skip header CRC data... 2299 */ 2300 2301 ptr += 2; 2302 2303 if (ptr > end) 2304 { 2305 /* 2306 * Can't read from file! 2307 */ 2308 2309 return (-1); 2310 } 2311 } 2312 2313 /* 2314 * Copy the flate-compressed data to the compression buffer... 2315 */ 2316 2317 if ((bytes = end - ptr) > 0) 2318 memcpy(fp->cbuf, ptr, bytes); 2319 2320 /* 2321 * Setup the decompressor data... 2322 */ 2323 2324 fp->stream.zalloc = (alloc_func)0; 2325 fp->stream.zfree = (free_func)0; 2326 fp->stream.opaque = (voidpf)0; 2327 fp->stream.next_in = (Bytef *)fp->cbuf; 2328 fp->stream.next_out = NULL; 2329 fp->stream.avail_in = bytes; 2330 fp->stream.avail_out = 0; 2331 fp->crc = crc32(0L, Z_NULL, 0); 2332 2333 if (inflateInit2(&(fp->stream), -15) != Z_OK) 2334 return (-1); 2335 2336 fp->compressed = 1; 2337 } 2338 2339 if (fp->compressed) 2340 { 2341 /* 2342 * If we have reached end-of-file, return immediately... 2343 */ 2344 2345 if (fp->eof) 2346 return (-1); 2347 2348 /* 2349 * Fill the decompression buffer as needed... 2350 */ 2351 2352 if (fp->stream.avail_in == 0) 2353 { 2354 if ((bytes = cups_read(fp, (char *)fp->cbuf, sizeof(fp->cbuf))) <= 0) 2355 return (-1); 2356 2357 fp->stream.next_in = fp->cbuf; 2358 fp->stream.avail_in = bytes; 2359 } 2360 2361 /* 2362 * Decompress data from the buffer... 2363 */ 2364 2365 fp->stream.next_out = (Bytef *)fp->buf; 2366 fp->stream.avail_out = sizeof(fp->buf); 2367 2368 status = inflate(&(fp->stream), Z_NO_FLUSH); 2369 2370 if (fp->stream.next_out > (Bytef *)fp->buf) 2371 fp->crc = crc32(fp->crc, (Bytef *)fp->buf, 2372 fp->stream.next_out - (Bytef *)fp->buf); 2373 2374 if (status == Z_STREAM_END) 2375 { 2376 /* 2377 * Read the CRC and length... 2378 */ 2379 2380 unsigned char trailer[8]; /* Trailer bytes */ 2381 uLong tcrc; /* Trailer CRC */ 2382 2383 2384 if (read(fp->fd, trailer, sizeof(trailer)) < sizeof(trailer)) 2385 { 2386 /* 2387 * Can't get it, so mark end-of-file... 2388 */ 2389 2390 fp->eof = 1; 2391 } 2392 else 2393 { 2394 tcrc = ((((((uLong)trailer[3] << 8) | (uLong)trailer[2]) << 8) | 2395 (uLong)trailer[1]) << 8) | (uLong)trailer[0]; 2396 2397 if (tcrc != fp->crc) 2398 { 2399 /* 2400 * Bad CRC, mark end-of-file... 2401 */ 2402 2403 DEBUG_printf(("9cups_fill: tcrc=%08x != fp->crc=%08x", 2404 (unsigned int)tcrc, (unsigned int)fp->crc)); 2405 2406 fp->eof = 1; 2407 2408 return (-1); 2409 } 2410 2411 /* 2412 * Otherwise, reset the compressed flag so that we re-read the 2413 * file header... 2414 */ 2415 2416 fp->compressed = 0; 2417 } 2418 } 2419 2420 bytes = sizeof(fp->buf) - fp->stream.avail_out; 2421 2422 /* 2423 * Return the decompressed data... 2424 */ 2425 2426 fp->ptr = fp->buf; 2427 fp->end = fp->buf + bytes; 2428 2429 if (bytes) 2430 return (bytes); 2431 } 2432 } 2433#endif /* HAVE_LIBZ */ 2434 2435 /* 2436 * Read a buffer's full of data... 2437 */ 2438 2439 if ((bytes = cups_read(fp, fp->buf, sizeof(fp->buf))) <= 0) 2440 { 2441 /* 2442 * Can't read from file! 2443 */ 2444 2445 fp->eof = 1; 2446 fp->ptr = fp->buf; 2447 fp->end = fp->buf; 2448 2449 return (-1); 2450 } 2451 2452 /* 2453 * Return the bytes we read... 2454 */ 2455 2456 fp->eof = 0; 2457 fp->ptr = fp->buf; 2458 fp->end = fp->buf + bytes; 2459 2460 return (bytes); 2461} 2462 2463 2464/* 2465 * 'cups_open()' - Safely open a file for writing. 2466 * 2467 * We don't allow appending to directories or files that are hard-linked or 2468 * symlinked. 2469 */ 2470 2471static int /* O - File descriptor or -1 otherwise */ 2472cups_open(const char *filename, /* I - Filename */ 2473 int mode) /* I - Open mode */ 2474{ 2475 int fd; /* File descriptor */ 2476 struct stat fileinfo; /* File information */ 2477#ifndef WIN32 2478 struct stat linkinfo; /* Link information */ 2479#endif /* !WIN32 */ 2480 2481 2482 /* 2483 * Open the file... 2484 */ 2485 2486 if ((fd = open(filename, mode, 0666)) < 0) 2487 return (-1); 2488 2489 /* 2490 * Then verify that the file descriptor doesn't point to a directory or hard- 2491 * linked file. 2492 */ 2493 2494 if (fstat(fd, &fileinfo)) 2495 { 2496 close(fd); 2497 return (-1); 2498 } 2499 2500 if (fileinfo.st_nlink != 1) 2501 { 2502 close(fd); 2503 errno = EPERM; 2504 return (-1); 2505 } 2506 2507#ifdef WIN32 2508 if (fileinfo.st_mode & _S_IFDIR) 2509#else 2510 if (S_ISDIR(fileinfo.st_mode)) 2511#endif /* WIN32 */ 2512 { 2513 close(fd); 2514 errno = EISDIR; 2515 return (-1); 2516 } 2517 2518#ifndef WIN32 2519 /* 2520 * Then use lstat to determine whether the filename is a symlink... 2521 */ 2522 2523 if (lstat(filename, &linkinfo)) 2524 { 2525 close(fd); 2526 return (-1); 2527 } 2528 2529 if (S_ISLNK(linkinfo.st_mode) || 2530 fileinfo.st_dev != linkinfo.st_dev || 2531 fileinfo.st_ino != linkinfo.st_ino || 2532#ifdef HAVE_ST_GEN 2533 fileinfo.st_gen != linkinfo.st_gen || 2534#endif /* HAVE_ST_GEN */ 2535 fileinfo.st_nlink != linkinfo.st_nlink || 2536 fileinfo.st_mode != linkinfo.st_mode) 2537 { 2538 /* 2539 * Yes, don't allow! 2540 */ 2541 2542 close(fd); 2543 errno = EPERM; 2544 return (-1); 2545 } 2546#endif /* !WIN32 */ 2547 2548 return (fd); 2549} 2550 2551 2552/* 2553 * 'cups_read()' - Read from a file descriptor. 2554 */ 2555 2556static ssize_t /* O - Number of bytes read or -1 */ 2557cups_read(cups_file_t *fp, /* I - CUPS file */ 2558 char *buf, /* I - Buffer */ 2559 size_t bytes) /* I - Number bytes */ 2560{ 2561 ssize_t total; /* Total bytes read */ 2562 2563 2564 DEBUG_printf(("7cups_read(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf, 2565 CUPS_LLCAST bytes)); 2566 2567 /* 2568 * Loop until we read at least 0 bytes... 2569 */ 2570 2571 for (;;) 2572 { 2573#ifdef WIN32 2574 if (fp->mode == 's') 2575 total = (ssize_t)recv(fp->fd, buf, (unsigned)bytes, 0); 2576 else 2577 total = (ssize_t)read(fp->fd, buf, (unsigned)bytes); 2578#else 2579 if (fp->mode == 's') 2580 total = recv(fp->fd, buf, bytes, 0); 2581 else 2582 total = read(fp->fd, buf, bytes); 2583#endif /* WIN32 */ 2584 2585 DEBUG_printf(("9cups_read: total=" CUPS_LLFMT, CUPS_LLCAST total)); 2586 2587 if (total >= 0) 2588 break; 2589 2590 /* 2591 * Reads can be interrupted by signals and unavailable resources... 2592 */ 2593 2594 if (errno == EAGAIN || errno == EINTR) 2595 continue; 2596 else 2597 return (-1); 2598 } 2599 2600 /* 2601 * Return the total number of bytes read... 2602 */ 2603 2604 return (total); 2605} 2606 2607 2608/* 2609 * 'cups_write()' - Write to a file descriptor. 2610 */ 2611 2612static ssize_t /* O - Number of bytes written or -1 */ 2613cups_write(cups_file_t *fp, /* I - CUPS file */ 2614 const char *buf, /* I - Buffer */ 2615 size_t bytes) /* I - Number bytes */ 2616{ 2617 size_t total; /* Total bytes written */ 2618 ssize_t count; /* Count this time */ 2619 2620 2621 DEBUG_printf(("7cups_write(fp=%p, buf=%p, bytes=" CUPS_LLFMT ")", fp, buf, 2622 CUPS_LLCAST bytes)); 2623 2624 /* 2625 * Loop until all bytes are written... 2626 */ 2627 2628 total = 0; 2629 while (bytes > 0) 2630 { 2631#ifdef WIN32 2632 if (fp->mode == 's') 2633 count = (ssize_t)send(fp->fd, buf, (unsigned)bytes, 0); 2634 else 2635 count = (ssize_t)write(fp->fd, buf, (unsigned)bytes); 2636#else 2637 if (fp->mode == 's') 2638 count = send(fp->fd, buf, bytes, 0); 2639 else 2640 count = write(fp->fd, buf, bytes); 2641#endif /* WIN32 */ 2642 2643 DEBUG_printf(("9cups_write: count=" CUPS_LLFMT, CUPS_LLCAST count)); 2644 2645 if (count < 0) 2646 { 2647 /* 2648 * Writes can be interrupted by signals and unavailable resources... 2649 */ 2650 2651 if (errno == EAGAIN || errno == EINTR) 2652 continue; 2653 else 2654 return (-1); 2655 } 2656 2657 /* 2658 * Update the counts for the last write call... 2659 */ 2660 2661 bytes -= count; 2662 total += count; 2663 buf += count; 2664 } 2665 2666 /* 2667 * Return the total number of bytes written... 2668 */ 2669 2670 return ((ssize_t)total); 2671} 2672 2673 2674/* 2675 * End of "$Id: file.c 11693 2014-03-11 01:24:45Z msweet $". 2676 */ 2677