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