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