1 /* 2 * File test program for CUPS. 3 * 4 * Copyright 2007-2015 by Apple Inc. 5 * Copyright 1997-2007 by Easy Software Products. 6 * 7 * These coded instructions, statements, and computer programs are the 8 * property of Apple Inc. and are protected by Federal copyright 9 * law. Distribution and use rights are outlined in the file "LICENSE.txt" 10 * which should have been included with this file. If this file is 11 * missing or damaged, see the license at "http://www.cups.org/". 12 * 13 * This file is subject to the Apple OS-Developed Software exception. 14 */ 15 16 /* 17 * Include necessary headers... 18 */ 19 20 #include "string-private.h" 21 #include "debug-private.h" 22 #include "file.h" 23 #include <stdlib.h> 24 #include <time.h> 25 #ifdef HAVE_LIBZ 26 # include <zlib.h> 27 #endif /* HAVE_LIBZ */ 28 #ifdef WIN32 29 # include <io.h> 30 #else 31 # include <unistd.h> 32 #endif /* WIN32 */ 33 #include <fcntl.h> 34 35 36 /* 37 * Local functions... 38 */ 39 40 static int count_lines(cups_file_t *fp); 41 static int random_tests(void); 42 static int read_write_tests(int compression); 43 44 45 /* 46 * 'main()' - Main entry. 47 */ 48 49 int /* O - Exit status */ 50 main(int argc, /* I - Number of command-line arguments */ 51 char *argv[]) /* I - Command-line arguments */ 52 { 53 int status; /* Exit status */ 54 char filename[1024]; /* Filename buffer */ 55 cups_file_t *fp; /* File pointer */ 56 #ifndef WIN32 57 int fds[2]; /* Open file descriptors */ 58 cups_file_t *fdfile; /* File opened with cupsFileOpenFd() */ 59 #endif /* !WIN32 */ 60 int count; /* Number of lines in file */ 61 62 63 if (argc == 1) 64 { 65 /* 66 * Do uncompressed file tests... 67 */ 68 69 status = read_write_tests(0); 70 71 #ifdef HAVE_LIBZ 72 /* 73 * Do compressed file tests... 74 */ 75 76 putchar('\n'); 77 78 status += read_write_tests(1); 79 #endif /* HAVE_LIBZ */ 80 81 /* 82 * Do uncompressed random I/O tests... 83 */ 84 85 status += random_tests(); 86 87 #ifndef WIN32 88 /* 89 * Test fdopen and close without reading... 90 */ 91 92 pipe(fds); 93 close(fds[1]); 94 95 fputs("\ncupsFileOpenFd(fd, \"r\"): ", stdout); 96 fflush(stdout); 97 98 if ((fdfile = cupsFileOpenFd(fds[0], "r")) == NULL) 99 { 100 puts("FAIL"); 101 status ++; 102 } 103 else 104 { 105 /* 106 * Able to open file, now close without reading. If we don't return 107 * before the alarm fires, that is a failure and we will crash on the 108 * alarm signal... 109 */ 110 111 puts("PASS"); 112 fputs("cupsFileClose(no read): ", stdout); 113 fflush(stdout); 114 115 alarm(5); 116 cupsFileClose(fdfile); 117 alarm(0); 118 119 puts("PASS"); 120 } 121 #endif /* !WIN32 */ 122 123 /* 124 * Count lines in psglyphs, rewind, then count again. 125 */ 126 127 fputs("\ncupsFileOpen(\"../data/media.defs\", \"r\"): ", stdout); 128 129 if ((fp = cupsFileOpen("../data/media.defs", "r")) == NULL) 130 { 131 puts("FAIL"); 132 status ++; 133 } 134 else 135 { 136 puts("PASS"); 137 fputs("cupsFileGets: ", stdout); 138 139 if ((count = count_lines(fp)) != 201) 140 { 141 printf("FAIL (got %d lines, expected 201)\n", count); 142 status ++; 143 } 144 else 145 { 146 puts("PASS"); 147 fputs("cupsFileRewind: ", stdout); 148 149 if (cupsFileRewind(fp) != 0) 150 { 151 puts("FAIL"); 152 status ++; 153 } 154 else 155 { 156 puts("PASS"); 157 fputs("cupsFileGets: ", stdout); 158 159 if ((count = count_lines(fp)) != 201) 160 { 161 printf("FAIL (got %d lines, expected 201)\n", count); 162 status ++; 163 } 164 else 165 puts("PASS"); 166 } 167 } 168 169 cupsFileClose(fp); 170 } 171 172 /* 173 * Test path functions... 174 */ 175 176 fputs("\ncupsFileFind: ", stdout); 177 #ifdef WIN32 178 if (cupsFileFind("notepad.exe", "C:/WINDOWS", 1, filename, sizeof(filename)) && 179 cupsFileFind("notepad.exe", "C:/WINDOWS;C:/WINDOWS/SYSTEM32", 1, filename, sizeof(filename))) 180 #else 181 if (cupsFileFind("cat", "/bin", 1, filename, sizeof(filename)) && 182 cupsFileFind("cat", "/bin:/usr/bin", 1, filename, sizeof(filename))) 183 #endif /* WIN32 */ 184 printf("PASS (%s)\n", filename); 185 else 186 { 187 puts("FAIL"); 188 status ++; 189 } 190 191 /* 192 * Summarize the results and return... 193 */ 194 195 if (!status) 196 puts("\nALL TESTS PASSED!"); 197 else 198 printf("\n%d TEST(S) FAILED!\n", status); 199 } 200 else 201 { 202 /* 203 * Cat the filename on the command-line... 204 */ 205 206 char line[8192]; /* Line from file */ 207 208 if ((fp = cupsFileOpen(argv[1], "r")) == NULL) 209 { 210 perror(argv[1]); 211 status = 1; 212 } 213 else if (argc == 2) 214 { 215 status = 0; 216 217 while (cupsFileGets(fp, line, sizeof(line))) 218 puts(line); 219 220 if (!cupsFileEOF(fp)) 221 perror(argv[1]); 222 223 cupsFileClose(fp); 224 } 225 else 226 { 227 status = 0; 228 ssize_t bytes; 229 230 while ((bytes = cupsFileRead(fp, line, sizeof(line))) > 0) 231 printf("%s: %d bytes\n", argv[1], (int)bytes); 232 233 if (cupsFileEOF(fp)) 234 printf("%s: EOF\n", argv[1]); 235 else 236 perror(argv[1]); 237 238 cupsFileClose(fp); 239 } 240 } 241 242 return (status); 243 } 244 245 246 /* 247 * 'count_lines()' - Count the number of lines in a file. 248 */ 249 250 static int /* O - Number of lines */ 251 count_lines(cups_file_t *fp) /* I - File to read from */ 252 { 253 int count; /* Number of lines */ 254 char line[1024]; /* Line buffer */ 255 256 257 for (count = 0; cupsFileGets(fp, line, sizeof(line)); count ++); 258 259 return (count); 260 } 261 262 263 /* 264 * 'random_tests()' - Do random access tests. 265 */ 266 267 static int /* O - Status */ 268 random_tests(void) 269 { 270 int status, /* Status of tests */ 271 pass, /* Current pass */ 272 count, /* Number of records read */ 273 record, /* Current record */ 274 num_records; /* Number of records */ 275 off_t pos; /* Position in file */ 276 ssize_t expected; /* Expected position in file */ 277 cups_file_t *fp; /* File */ 278 char buffer[512]; /* Data buffer */ 279 280 281 /* 282 * Run 4 passes, each time appending to a data file and then reopening the 283 * file for reading to validate random records in the file. 284 */ 285 286 for (status = 0, pass = 0; pass < 4; pass ++) 287 { 288 /* 289 * cupsFileOpen(append) 290 */ 291 292 printf("\ncupsFileOpen(append %d): ", pass); 293 294 if ((fp = cupsFileOpen("testfile.dat", "a")) == NULL) 295 { 296 printf("FAIL (%s)\n", strerror(errno)); 297 status ++; 298 break; 299 } 300 else 301 puts("PASS"); 302 303 /* 304 * cupsFileTell() 305 */ 306 307 expected = 256 * (ssize_t)sizeof(buffer) * pass; 308 309 fputs("cupsFileTell(): ", stdout); 310 if ((pos = cupsFileTell(fp)) != (off_t)expected) 311 { 312 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", 313 CUPS_LLCAST pos, CUPS_LLCAST expected); 314 status ++; 315 break; 316 } 317 else 318 puts("PASS"); 319 320 /* 321 * cupsFileWrite() 322 */ 323 324 fputs("cupsFileWrite(256 512-byte records): ", stdout); 325 for (record = 0; record < 256; record ++) 326 { 327 memset(buffer, record, sizeof(buffer)); 328 if (cupsFileWrite(fp, buffer, sizeof(buffer)) < (ssize_t)sizeof(buffer)) 329 break; 330 } 331 332 if (record < 256) 333 { 334 printf("FAIL (%d: %s)\n", record, strerror(errno)); 335 status ++; 336 break; 337 } 338 else 339 puts("PASS"); 340 341 /* 342 * cupsFileTell() 343 */ 344 345 expected += 256 * (ssize_t)sizeof(buffer); 346 347 fputs("cupsFileTell(): ", stdout); 348 if ((pos = cupsFileTell(fp)) != (off_t)expected) 349 { 350 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", 351 CUPS_LLCAST pos, CUPS_LLCAST expected); 352 status ++; 353 break; 354 } 355 else 356 puts("PASS"); 357 358 cupsFileClose(fp); 359 360 /* 361 * cupsFileOpen(read) 362 */ 363 364 printf("\ncupsFileOpen(read %d): ", pass); 365 366 if ((fp = cupsFileOpen("testfile.dat", "r")) == NULL) 367 { 368 printf("FAIL (%s)\n", strerror(errno)); 369 status ++; 370 break; 371 } 372 else 373 puts("PASS"); 374 375 /* 376 * cupsFileSeek, cupsFileRead 377 */ 378 379 fputs("cupsFileSeek(), cupsFileRead(): ", stdout); 380 381 for (num_records = (pass + 1) * 256, count = (pass + 1) * 256, record = ((int)CUPS_RAND() & 65535) % num_records; 382 count > 0; 383 count --, record = (record + ((int)CUPS_RAND() & 31) - 16 + num_records) % num_records) 384 { 385 /* 386 * The last record is always the first... 387 */ 388 389 if (count == 1) 390 record = 0; 391 392 /* 393 * Try reading the data for the specified record, and validate the 394 * contents... 395 */ 396 397 expected = (ssize_t)sizeof(buffer) * record; 398 399 if ((pos = cupsFileSeek(fp, expected)) != expected) 400 { 401 printf("FAIL (" CUPS_LLFMT " instead of " CUPS_LLFMT ")\n", 402 CUPS_LLCAST pos, CUPS_LLCAST expected); 403 status ++; 404 break; 405 } 406 else 407 { 408 if (cupsFileRead(fp, buffer, sizeof(buffer)) != sizeof(buffer)) 409 { 410 printf("FAIL (%s)\n", strerror(errno)); 411 status ++; 412 break; 413 } 414 else if ((buffer[0] & 255) != (record & 255) || 415 memcmp(buffer, buffer + 1, sizeof(buffer) - 1)) 416 { 417 printf("FAIL (Bad Data - %d instead of %d)\n", buffer[0] & 255, 418 record & 255); 419 status ++; 420 break; 421 } 422 } 423 } 424 425 if (count == 0) 426 puts("PASS"); 427 428 cupsFileClose(fp); 429 } 430 431 /* 432 * Remove the test file... 433 */ 434 435 unlink("testfile.dat"); 436 437 /* 438 * Return the test status... 439 */ 440 441 return (status); 442 } 443 444 445 /* 446 * 'read_write_tests()' - Perform read/write tests. 447 */ 448 449 static int /* O - Status */ 450 read_write_tests(int compression) /* I - Use compression? */ 451 { 452 int i; /* Looping var */ 453 cups_file_t *fp; /* File */ 454 int status; /* Exit status */ 455 char line[1024], /* Line from file */ 456 *value; /* Directive value from line */ 457 int linenum; /* Line number */ 458 unsigned char readbuf[8192], /* Read buffer */ 459 writebuf[8192]; /* Write buffer */ 460 int byte; /* Byte from file */ 461 ssize_t bytes; /* Number of bytes read/written */ 462 off_t length; /* Length of file */ 463 static const char *partial_line = "partial line"; 464 /* Partial line */ 465 466 467 /* 468 * No errors so far... 469 */ 470 471 status = 0; 472 473 /* 474 * Initialize the write buffer with random data... 475 */ 476 477 CUPS_SRAND((unsigned)time(NULL)); 478 479 for (i = 0; i < (int)sizeof(writebuf); i ++) 480 writebuf[i] = (unsigned char)CUPS_RAND(); 481 482 /* 483 * cupsFileOpen(write) 484 */ 485 486 printf("cupsFileOpen(write%s): ", compression ? " compressed" : ""); 487 488 fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", 489 compression ? "w9" : "w"); 490 if (fp) 491 { 492 puts("PASS"); 493 494 /* 495 * cupsFileCompression() 496 */ 497 498 fputs("cupsFileCompression(): ", stdout); 499 500 if (cupsFileCompression(fp) == compression) 501 puts("PASS"); 502 else 503 { 504 printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), 505 compression); 506 status ++; 507 } 508 509 /* 510 * cupsFilePuts() 511 */ 512 513 fputs("cupsFilePuts(): ", stdout); 514 515 if (cupsFilePuts(fp, "# Hello, World\n") > 0) 516 puts("PASS"); 517 else 518 { 519 printf("FAIL (%s)\n", strerror(errno)); 520 status ++; 521 } 522 523 /* 524 * cupsFilePrintf() 525 */ 526 527 fputs("cupsFilePrintf(): ", stdout); 528 529 for (i = 0; i < 1000; i ++) 530 if (cupsFilePrintf(fp, "TestLine %03d\n", i) < 0) 531 break; 532 533 if (i >= 1000) 534 puts("PASS"); 535 else 536 { 537 printf("FAIL (%s)\n", strerror(errno)); 538 status ++; 539 } 540 541 /* 542 * cupsFilePutChar() 543 */ 544 545 fputs("cupsFilePutChar(): ", stdout); 546 547 for (i = 0; i < 256; i ++) 548 if (cupsFilePutChar(fp, i) < 0) 549 break; 550 551 if (i >= 256) 552 puts("PASS"); 553 else 554 { 555 printf("FAIL (%s)\n", strerror(errno)); 556 status ++; 557 } 558 559 /* 560 * cupsFileWrite() 561 */ 562 563 fputs("cupsFileWrite(): ", stdout); 564 565 for (i = 0; i < 10000; i ++) 566 if (cupsFileWrite(fp, (char *)writebuf, sizeof(writebuf)) < 0) 567 break; 568 569 if (i >= 10000) 570 puts("PASS"); 571 else 572 { 573 printf("FAIL (%s)\n", strerror(errno)); 574 status ++; 575 } 576 577 /* 578 * cupsFilePuts() with partial line... 579 */ 580 581 fputs("cupsFilePuts(\"partial line\"): ", stdout); 582 583 if (cupsFilePuts(fp, partial_line) > 0) 584 puts("PASS"); 585 else 586 { 587 printf("FAIL (%s)\n", strerror(errno)); 588 status ++; 589 } 590 591 /* 592 * cupsFileTell() 593 */ 594 595 fputs("cupsFileTell(): ", stdout); 596 597 if ((length = cupsFileTell(fp)) == 81933283) 598 puts("PASS"); 599 else 600 { 601 printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length); 602 status ++; 603 } 604 605 /* 606 * cupsFileClose() 607 */ 608 609 fputs("cupsFileClose(): ", stdout); 610 611 if (!cupsFileClose(fp)) 612 puts("PASS"); 613 else 614 { 615 printf("FAIL (%s)\n", strerror(errno)); 616 status ++; 617 } 618 } 619 else 620 { 621 printf("FAIL (%s)\n", strerror(errno)); 622 status ++; 623 } 624 625 /* 626 * cupsFileOpen(read) 627 */ 628 629 fputs("\ncupsFileOpen(read): ", stdout); 630 631 fp = cupsFileOpen(compression ? "testfile.dat.gz" : "testfile.dat", "r"); 632 if (fp) 633 { 634 puts("PASS"); 635 636 /* 637 * cupsFileGets() 638 */ 639 640 fputs("cupsFileGets(): ", stdout); 641 642 if (cupsFileGets(fp, line, sizeof(line))) 643 { 644 if (line[0] == '#') 645 puts("PASS"); 646 else 647 { 648 printf("FAIL (Got line \"%s\", expected comment line)\n", line); 649 status ++; 650 } 651 } 652 else 653 { 654 printf("FAIL (%s)\n", strerror(errno)); 655 status ++; 656 } 657 658 /* 659 * cupsFileCompression() 660 */ 661 662 fputs("cupsFileCompression(): ", stdout); 663 664 if (cupsFileCompression(fp) == compression) 665 puts("PASS"); 666 else 667 { 668 printf("FAIL (Got %d, expected %d)\n", cupsFileCompression(fp), 669 compression); 670 status ++; 671 } 672 673 /* 674 * cupsFileGetConf() 675 */ 676 677 linenum = 1; 678 679 fputs("cupsFileGetConf(): ", stdout); 680 681 for (i = 0, value = NULL; i < 1000; i ++) 682 if (!cupsFileGetConf(fp, line, sizeof(line), &value, &linenum)) 683 break; 684 else if (_cups_strcasecmp(line, "TestLine") || !value || atoi(value) != i || 685 linenum != (i + 2)) 686 break; 687 688 if (i >= 1000) 689 puts("PASS"); 690 else if (line[0]) 691 { 692 printf("FAIL (Line %d, directive \"%s\", value \"%s\")\n", linenum, 693 line, value ? value : "(null)"); 694 status ++; 695 } 696 else 697 { 698 printf("FAIL (%s)\n", strerror(errno)); 699 status ++; 700 } 701 702 /* 703 * cupsFileGetChar() 704 */ 705 706 fputs("cupsFileGetChar(): ", stdout); 707 708 for (i = 0, byte = 0; i < 256; i ++) 709 if ((byte = cupsFileGetChar(fp)) != i) 710 break; 711 712 if (i >= 256) 713 puts("PASS"); 714 else if (byte >= 0) 715 { 716 printf("FAIL (Got %d, expected %d)\n", byte, i); 717 status ++; 718 } 719 else 720 { 721 printf("FAIL (%s)\n", strerror(errno)); 722 status ++; 723 } 724 725 /* 726 * cupsFileRead() 727 */ 728 729 fputs("cupsFileRead(): ", stdout); 730 731 for (i = 0, bytes = 0; i < 10000; i ++) 732 if ((bytes = cupsFileRead(fp, (char *)readbuf, sizeof(readbuf))) < 0) 733 break; 734 else if (memcmp(readbuf, writebuf, sizeof(readbuf))) 735 break; 736 737 if (i >= 10000) 738 puts("PASS"); 739 else if (bytes > 0) 740 { 741 printf("FAIL (Pass %d, ", i); 742 743 for (i = 0; i < (int)sizeof(readbuf); i ++) 744 if (readbuf[i] != writebuf[i]) 745 break; 746 747 printf("match failed at offset %d - got %02X, expected %02X)\n", 748 i, readbuf[i], writebuf[i]); 749 } 750 else 751 { 752 printf("FAIL (%s)\n", strerror(errno)); 753 status ++; 754 } 755 756 /* 757 * cupsFileGetChar() with partial line... 758 */ 759 760 fputs("cupsFileGetChar(partial line): ", stdout); 761 762 for (i = 0; i < (int)strlen(partial_line); i ++) 763 if ((byte = cupsFileGetChar(fp)) < 0) 764 break; 765 else if (byte != partial_line[i]) 766 break; 767 768 if (!partial_line[i]) 769 puts("PASS"); 770 else 771 { 772 printf("FAIL (got '%c', expected '%c')\n", byte, partial_line[i]); 773 status ++; 774 } 775 776 /* 777 * cupsFileTell() 778 */ 779 780 fputs("cupsFileTell(): ", stdout); 781 782 if ((length = cupsFileTell(fp)) == 81933283) 783 puts("PASS"); 784 else 785 { 786 printf("FAIL (" CUPS_LLFMT " instead of 81933283)\n", CUPS_LLCAST length); 787 status ++; 788 } 789 790 /* 791 * cupsFileClose() 792 */ 793 794 fputs("cupsFileClose(): ", stdout); 795 796 if (!cupsFileClose(fp)) 797 puts("PASS"); 798 else 799 { 800 printf("FAIL (%s)\n", strerror(errno)); 801 status ++; 802 } 803 } 804 else 805 { 806 printf("FAIL (%s)\n", strerror(errno)); 807 status ++; 808 } 809 810 /* 811 * Remove the test file... 812 */ 813 814 if (!status) 815 unlink(compression ? "testfile.dat.gz" : "testfile.dat"); 816 817 /* 818 * Return the test status... 819 */ 820 821 return (status); 822 } 823