source: rtems/testsuites/psxtests/psxfile01/test.c @ 3825926

5
Last change on this file since 3825926 was 3825926, checked in by Sebastian Huber <sebastian.huber@…>, on 10/18/18 at 09:51:32

Support O_CLOEXEC open() flag

Make sure this flag is ignored and does not prevent a successful open.

Close #3547.

  • Property mode set to 100644
File size: 18.7 KB
Line 
1/**
2 *  @file
3 *
4 *  Simple test program to exercise some of the basic functionality of
5 *  POSIX Files and Directories Support.
6 *
7 *  This test assumes that the file system is initialized with the
8 *  following directory structure:
9 *
10 *  XXXX fill this in.
11 *    /
12 *    /dev
13 *    /dev/XXX   [where XXX includes at least console]
14 */
15
16/*
17 *  COPYRIGHT (c) 1989-2012.
18 *  On-Line Applications Research Corporation (OAR).
19 *
20 *  The license and distribution terms for this file may be
21 *  found in the file LICENSE in this distribution or at
22 *  http://www.rtems.org/license/LICENSE.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
29#include <stdio.h>
30
31#include <pmacros.h>
32#include <sys/types.h>
33#include <sys/stat.h>
34#include <fcntl.h>
35#include <unistd.h>
36#include <errno.h>
37#include <string.h>
38#include <inttypes.h>
39#include <ctype.h>
40#include <reent.h>
41#include <rtems/imfs.h>
42
43#include <rtems.h>
44#include <rtems/libio.h>
45
46#include "primode.h"
47
48const char rtems_test_name[] = "PSXFILE 1";
49
50/* forward declarations to avoid warnings */
51void test_case_reopen_append(void);
52void dump_statbuf(struct stat *buf);
53void stat_a_file(const char *file);
54int test_main(void);
55
56char test_write_buffer[ 1024 ];
57rtems_filesystem_operations_table  IMFS_ops_no_evalformake;
58rtems_filesystem_operations_table  IMFS_ops_no_rename;
59
60static const char somefile[] = "somefile";
61
62/*
63 *  File test support routines.
64 */
65
66void test_cat(
67  char *file,
68  int   offset_arg,
69  int   length
70);
71
72void test_write(
73  char   *file,
74  off_t  offset,
75  char  *buffer
76);
77
78void test_extend(
79  char *file,
80  off_t new_len
81);
82
83/*
84 *  dump_statbuf
85 */
86void dump_statbuf( struct stat *buf )
87{
88  rtems_device_major_number major1;
89  rtems_device_minor_number minor1;
90  rtems_device_major_number major2;
91  rtems_device_minor_number minor2;
92
93  rtems_filesystem_split_dev_t( buf->st_dev, major1, minor1 );
94  rtems_filesystem_split_dev_t( buf->st_rdev, major2, minor2 );
95
96  printf( "....st_dev     (0x%" PRIx32 ":0x%" PRIx32 ")\n", major1, minor1 );
97  printf( "....st_rdev    (0x%" PRIx32 ":0x%" PRIx32 ")\n", major2, minor2 );
98  printf( "....st_ino     %" PRIxino_t "  may vary by small amount\n", buf->st_ino );
99  printf( "....mode  = %08" PRIomode_t "\n", buf->st_mode );
100  printf( "....nlink = %d\n", buf->st_nlink );
101
102  printf( "....uid = %d\n", buf->st_uid );
103  printf( "....gid = %d\n", buf->st_gid );
104
105  printf( "....atime = %s", ctime(&buf->st_atime) );
106  printf( "....mtime = %s", ctime(&buf->st_mtime) );
107  printf( "....ctime = %s", ctime(&buf->st_ctime) );
108
109  printf( "....st_blksize %" PRIxblksize_t "\n", buf->st_blksize );
110  printf( "....st_blocks  %" PRIxblkcnt_t "\n", buf->st_blocks );
111}
112
113void stat_a_file(
114  const char *file
115)
116{
117  int         status;
118  struct stat statbuf;
119
120  rtems_test_assert( file );
121
122  printf( "stat( %s ) returned ", file );
123
124  status = stat( file, &statbuf );
125
126  if ( status == -1 ) {
127    printf( ": %s\n", strerror( errno ) );
128  } else {
129    puts("");
130    dump_statbuf( &statbuf );
131  }
132
133}
134
135static void test_open_directory(void)
136{
137  int status;
138  int fd;
139
140  fd = open( somefile, O_CREAT, S_IRWXU );
141  rtems_test_assert( fd >= 0 );
142
143  status = close( fd );
144  rtems_test_assert( status == 0 );
145
146#ifdef O_DIRECTORY
147  errno = 0;
148  fd = open( somefile, O_DIRECTORY, S_IRWXU );
149  rtems_test_assert( fd == -1 );
150  rtems_test_assert( errno == ENOTDIR );
151#endif
152
153  status = unlink( somefile );
154  rtems_test_assert( status == 0 );
155}
156
157static void test_open_cloexec(void)
158{
159  int status;
160  int fd;
161  mode_t mode;
162
163  mode = O_CREAT;
164
165#ifdef O_CLOEXEC
166  mode |= O_CLOEXEC;
167#endif
168
169  fd = open( somefile, mode, S_IRWXU );
170  rtems_test_assert( fd >= 0 );
171
172  status = close( fd );
173  rtems_test_assert( status == 0 );
174
175  status = unlink( somefile );
176  rtems_test_assert( status == 0 );
177}
178
179/*
180 *  Main entry point of the test
181 */
182
183#if defined(__rtems__)
184int test_main(void)
185#else
186int main(
187  int argc,
188  char **argv
189)
190#endif
191{
192  int               status;
193  size_t            max_size;
194  int               fd;
195  int               i;
196  struct stat       buf;
197  char              buffer[128];
198  FILE             *file;
199  time_t            atime1;
200  time_t            mtime1;
201  time_t            ctime1;
202  time_t            atime2;
203  time_t            mtime2;
204  time_t            ctime2;
205  rtems_status_code rtems_status;
206  rtems_time_of_day time;
207
208  TEST_BEGIN();
209
210  test_open_directory();
211  test_open_cloexec();
212
213  /*
214   *  Grab the maximum size of an in-memory file.
215   */
216
217  max_size = IMFS_MEMFILE_MAXIMUM_SIZE;
218
219  build_time( &time, 12, 31, 1988, 9, 0, 0, 0 );
220  rtems_status = rtems_clock_set( &time );
221  directive_failed( rtems_status, "clock set" );
222
223  /*
224   *  Simple stat() of /dev/console.
225   */
226
227  puts( "stat of /dev/console" );
228  status = stat( "/dev/console", &buf );
229  rtems_test_assert( !status );
230
231  dump_statbuf( &buf );
232
233  /*
234   *  Exercise mkdir() and some path evaluation.
235   */
236
237  puts( "" );
238  puts( "mkdir /dev/tty" );
239  status = mkdir( "/dev/tty", S_IRWXU );
240  rtems_test_assert( !status );
241
242  puts( "" );
243  puts( "mkdir /usr" );
244  status = mkdir( "/usr", S_IRWXU );
245  rtems_test_assert( !status );
246  puts( "mkdir /etc" );
247  status = mkdir( "/etc", S_IRWXU );
248  rtems_test_assert( !status );
249
250  puts( "mkdir /tmp" );
251  status = mkdir( "/tmp", S_IRWXU );
252  rtems_test_assert( !status );
253
254  /* this tests the ".." path in path name evaluation */
255  puts( "mkdir /tmp/.." );
256  status = mkdir( "/tmp/..", S_IRWXU );
257  rtems_test_assert( status == -1 );
258  rtems_test_assert( errno == EEXIST );
259
260  /* now check out trailing separators */
261  puts( "mkdir /tmp/" );
262  status = mkdir( "/tmp/", S_IRWXU );
263  rtems_test_assert( status == -1 );
264  rtems_test_assert( errno == EEXIST );
265
266  /* try to make a directory under a non-existent subdirectory */
267  puts( "mkdir /j/j1" );
268  status = mkdir( "/j/j1", S_IRWXU );
269  rtems_test_assert( status == -1 );
270  rtems_test_assert( errno == ENOENT );
271
272  /* this tests the ability to make a directory in the current one */
273  puts( "mkdir tmp" );
274  status = mkdir( "tmp", S_IRWXU );
275  rtems_test_assert( status == -1 );
276  rtems_test_assert( errno == EEXIST );
277
278  /*
279   *  Now switch gears and exercise rmdir().
280   */
281
282  puts( "" );
283  puts( "rmdir /usr" );
284  status = rmdir( "/usr" );
285  rtems_test_assert( !status );
286
287  puts( "rmdir /dev" );
288  status = rmdir( "/dev" );
289  rtems_test_assert( status == -1 );
290  rtems_test_assert( errno ==  ENOTEMPTY);
291
292  puts( "rmdir /fred" );
293  status = rmdir ("/fred");
294  rtems_test_assert (status == -1);
295  rtems_test_assert( errno == ENOENT );
296
297  puts( "rmdir /tmp/bha" );
298  status = rmdir( "/tmp/bha" );
299  rtems_test_assert( status == -1 );
300  rtems_test_assert( errno == ENOENT );
301
302  puts( "mknod /dev/test_console" );
303  status = mknod( "/dev/test_console", S_IFCHR, 0LL );
304  rtems_test_assert( !status );
305
306  puts( "mknod /dev/tty/S3" );
307  status = mknod( "/dev/tty/S3", S_IFCHR, 0xFF00000080LL );
308  rtems_test_assert( !status );
309
310  puts ("mknod /etc/passwd");
311  status = mknod( "/etc/passwd", (S_IFREG | S_IRWXU), 0LL );
312  rtems_test_assert( !status );
313
314  puts( "mkdir /tmp/my_dir");
315  status = mkdir( "/tmp/my_dir", S_IRWXU );
316  rtems_test_assert( status == 0 );
317
318  puts("mkfifo /c/my_dir" );
319  status = mkfifo( "/c/my_dir", S_IRWXU );
320  rtems_test_assert( status == -1 );
321
322  /*
323   *  Try to make a directory under a file -- ERROR
324   */
325
326  puts( "mkdir /etc/passwd/j" );
327  status = mkdir( "/etc/passwd/j", S_IRWXU );
328  rtems_test_assert( status == -1 );
329  rtems_test_assert( errno == ENOTDIR );
330
331  /*
332   *  Simple open failure case on non-existent file
333   */
334
335  puts( "open /tmp/joel - should fail with ENOENT" );
336  fd = open( "/tmp/joel", O_RDONLY );
337  rtems_test_assert( fd == -1 );
338  rtems_test_assert( errno == ENOENT );
339
340  /*
341   *  Simple open case where the file is created.
342   */
343
344  puts( "open /tmp/j" );
345  fd = open( "/tmp/j", O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO );
346  rtems_test_assert( fd != -1 );
347  printf( "open returned file descriptor %d\n", fd );
348
349  puts( "close /tmp/j" );
350  status = close( fd );
351  rtems_test_assert( !status );
352
353  puts( "close /tmp/j again" );
354  status = close( fd );
355  rtems_test_assert( status == -1 );
356
357  puts( "unlink /tmp/j" );
358  status = unlink( "/tmp/j" );
359  rtems_test_assert( !status );
360
361  puts( "unlink /tmp" );
362  status = unlink( "/tmp" );
363  rtems_test_assert( status );
364
365  /*
366   *  Simple open failure. Trying to create an existing file.
367   */
368
369  puts("create and close /tmp/tom");
370  fd = open( "/tmp/tom", O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO );
371  rtems_test_assert( fd != -1 );
372  status = close( fd );
373  rtems_test_assert( status == 0 );
374
375  puts("Attempt to recreate /tmp/tom");
376  fd = open( "/tmp/tom", O_CREAT | O_EXCL, S_IRWXU|S_IRWXG|S_IRWXO );
377  rtems_test_assert( fd == -1 );
378  rtems_test_assert( errno == EEXIST );
379
380  puts("create /tmp/john");
381  fd = open( "/tmp/john", O_RDWR|O_CREAT, S_IRWXU|S_IRWXG|S_IRWXO );
382  rtems_test_assert( fd != -1 );
383  status = close( fd );
384  rtems_test_assert( status == 0 );
385
386  /*
387   * Open a file in read-only mode and try to truncate
388   */
389
390  puts( "Attempt to create a file, open in read-only mode and truncate it" );
391  fd = open( "/tmp/bha", O_CREAT | O_RDONLY | O_TRUNC, S_IRUSR );
392  rtems_test_assert( fd == -1 );
393  rtems_test_assert( errno == EINVAL );
394
395  puts( "Exercise the reentrant version _link_r -- Expect ENOENT" );
396  status = _link_r( NULL, "/tmp/notexist", "/tmp/cannotexist" );
397  rtems_test_assert( status == -1 );
398  rtems_test_assert( errno == ENOENT );
399
400  puts( "Unlink /tmp/bha using the reentrant version -- OK" );
401  status = _unlink_r( NULL, "/tmp/bha" );
402  rtems_test_assert( status == 0 );
403
404  /*
405   * Simple test case for mknod
406   */
407
408  puts( "mknod with bad type - expect EINVAL" );
409  status = mknod( "/tmp/bha", 0, 0LL );
410  rtems_test_assert( status == -1 );
411  rtems_test_assert( errno == EINVAL );
412
413  /*
414   * Read from filedes opened for write
415   */
416
417  puts( "open /tmp/bha in write only mode -- OK" );
418  fd = open( "/tmp/bha", O_CREAT | O_WRONLY, S_IRWXU|S_IRWXG|S_IRWXO );
419  rtems_test_assert( fd != -1 );
420
421  puts( "attempt fcntl on opened file -- OK" );
422  status = fcntl( fd, F_SETFD, 0 );
423  rtems_test_assert( status == 0 );
424
425  puts( "attempt to read from /tmp/bha - expect EBADF" );
426  status = read( fd, buffer, 10 );
427  rtems_test_assert( status == -1 );
428  rtems_test_assert( errno == EBADF );
429
430  puts( "closing and unlinking /tmp/bha" );
431  status = close( fd );
432  status |= unlink( "/tmp/bha" );
433  rtems_test_assert( status == 0 );
434
435  puts( "open /tmp/bha in read only mode -- OK" );
436  fd = open( "/tmp/bha", O_CREAT | O_RDONLY, S_IRWXU|S_IRWXG|S_IRWXO );
437  rtems_test_assert( fd != -1 );
438
439  puts( "attempt to read from /tmp/bha - expect EBADF" );
440  status = write( fd, buffer, 10 );
441  rtems_test_assert( status == -1 );
442  rtems_test_assert( errno == EBADF );
443
444  puts( "closing and unlinking /tmp/bha" );
445  status = close( fd );
446  status |= unlink( "/tmp/bha" );
447  rtems_test_assert( status == 0 );
448
449  /*
450   * Read/write from an unopened filedes
451   */
452  puts( "attempt to read from an unopened filedes - expect EBADF" );
453  status = read( 5, buffer, 10 );
454  rtems_test_assert( status == -1 );
455  rtems_test_assert( errno == EBADF );
456
457  puts( "attempt to write to an unopened filedes - expect EBADF" );
458  status = write( 5, buffer, 10 );
459  rtems_test_assert( status == -1 );
460  rtems_test_assert( errno == EBADF );
461
462  /*
463   *  Test simple write to a file at offset 0
464   */
465
466  puts( "mknod /tmp/joel" );
467  status = mknod( "/tmp/joel", (S_IFREG | S_IRWXU), 0LL );
468  test_write( "/tmp/joel", 0, "the first write!!!\n" );
469  test_cat( "/tmp/joel", 0, 0 );
470
471  /* Exercise _rename_r */
472
473  /* Simple rename test */
474  puts( "rename /tmp/joel to /tmp/drjoel");
475  status = _rename_r(NULL,"/tmp/joel","/tmp/drjoel");
476  rtems_test_assert(status == 0);
477
478  /* Simple rename test */
479  puts("rename /tmp/drjoel to /tmp/joel");
480  status = _rename_r(NULL,"/tmp/drjoel","/tmp/joel");
481  rtems_test_assert(status == 0);
482
483  /* Invalid old path */
484  puts("rename /tmp/drjoel to /tmp/joel - Should result in an error \
485since old path is not valid");
486  status = _rename_r(NULL,"/tmp/drjoel","/tmp/joel");
487  rtems_test_assert(status == -1);
488
489  /* Invalid new path */
490  puts("rename /tmp/joel to /tmp/drjoel/joel - Should result in an error \
491since new path is not valid");
492  status = _rename_r(NULL,"/tmp/joel","/tmp/drjoel/joel");
493  rtems_test_assert(status == -1);
494
495  puts("changing dir to /tmp");
496  status = chdir("/tmp/");
497  rtems_test_assert(status == 0);
498
499  puts("rename joel to drjoel");
500  status = _rename_r(NULL,"joel","drjoel");
501  rtems_test_assert(status == 0);
502
503  puts("rename drjoel to joel");
504  status = _rename_r(NULL,"drjoel","joel");
505  rtems_test_assert(status == 0);
506
507  /* Rename across file systems */
508  puts("creating directory /imfs");
509  status = mkdir("/imfs",0777);
510  rtems_test_assert(status == 0);
511  puts("creating directory /imfs/hidden_on_mount");
512  status = mkdir("/imfs/hidden_on_mount",0777);
513  rtems_test_assert(status == 0);
514
515  puts("mounting filesystem with IMFS_ops at /imfs");
516  status = mount("null", "/imfs", "imfs", RTEMS_FILESYSTEM_READ_WRITE, NULL);
517  rtems_test_assert(status == 0);
518  puts("creating directory /imfs/test (on newly mounted filesystem)");
519  status = mkdir("/imfs/test", 0777);
520  rtems_test_assert(status == 0);
521
522  puts("attempt to rename directory joel to /imfs/test/joel - should fail with EXDEV");
523  status = _rename_r(NULL, "joel", "/imfs/test/joel");
524  rtems_test_assert(status == -1);
525  rtems_test_assert(errno == EXDEV);
526
527  puts("changing dir to /");
528  status = chdir("/");
529  rtems_test_assert(status == 0);
530
531  puts("attempt to rename across filesystem, with old path having a parent node");
532  puts("attempt to rename tmp/joel to /imfs/test/joel");
533  status = _rename_r(NULL, "tmp/joel", "/imfs/test/joel");
534  rtems_test_assert(status == -1);
535  rtems_test_assert(errno == EXDEV);
536
537  puts("End of _rename_r tests");
538
539  /*
540   *  Test simple write to a file at a non-0 offset in the first block
541   */
542
543  status = unlink( "/tmp/joel" );
544  rtems_test_assert( !status );
545
546  status = mknod( "/tmp/joel", (S_IFREG | S_IRWXU), 0LL );
547  rtems_test_assert( !status );
548
549  test_write( "/tmp/joel", 10, "the first write!!!\n" );
550  test_cat( "/tmp/joel", 0, 0 );
551  stat_a_file( "/tmp/joel" );
552
553  /*
554   *  Test simple write to a file at a non-0 offset in the second block.  Then
555   *  try to read from various offsets and lengths.
556   */
557
558  puts("unlink /tmp/joel");
559  status = unlink( "/tmp/joel" );
560  rtems_test_assert( !status );
561
562  /* Test a failure path */
563
564  puts( "unlink /tmp/joel" );
565  status = unlink( "/tmp/joel" );
566  rtems_test_assert( status == -1 );
567
568  puts( "mknod /tmp/joel");
569  status = mknod( "/tmp/joel", (S_IFREG | S_IRWXU), 0LL );
570  rtems_test_assert( !status );
571
572  test_write( "/tmp/joel", 514, "the first write!!!\n" );
573  test_write( "/tmp/joel", 1, test_write_buffer );
574  test_write( "/tmp/joel", 63, test_write_buffer );
575  test_cat( "/tmp/joel", 0, 1 );
576  test_cat( "/tmp/joel", 1, 1 );
577  test_cat( "/tmp/joel", 490, 1 );
578  test_cat( "/tmp/joel", 512, 1 );
579  test_cat( "/tmp/joel", 513, 1 );
580  test_cat( "/tmp/joel", 514, 1 );
581  test_cat( "/tmp/joel", 520, 1 );
582  test_cat( "/tmp/joel", 1, 1024 );
583
584  /*
585   *  Read from a much longer file so we can descend into doubly and
586   *  triply indirect blocks.
587   */
588
589  if ( max_size < (size_t) 300 * 1024 ) {
590    test_extend( "/tmp/joel", max_size - 1 );
591    test_cat( "/tmp/joel", max_size / 2, 1024 );
592  } else {
593    printf( "Skipping maximum file size test since max_size is %zu bytes\n", max_size );
594    puts("That is likely to be bigger than the available RAM on many targets." );
595  }
596
597  stat_a_file( "/tmp/joel" );
598
599  /*
600   *  Now try to use a FILE * descriptor
601   *
602   *  /tmp/j should not exist at this point.
603   */
604
605  puts( "stat of /tmp/j" );
606  errno = 0;
607  status = stat( "/tmp/j", &buf );
608  printf( "stat(/tmp/j) returned %d (errno=%d)\n", status, errno );
609  dump_statbuf( &buf );
610
611  puts( "fopen of /tmp/j" );
612  file = fopen( "/tmp/j", "w+" );
613  rtems_test_assert( file );
614
615  puts( "fprintf to /tmp/j" );
616  for (i=1 ; i<=5 ; i++) {
617    status = fprintf( file, "This is call %d to fprintf\n", i );
618    rtems_test_assert( status );
619    printf( "(%d) %d characters written to the file\n", i, status );
620  }
621
622  fflush( file );
623
624  status = stat( "/tmp/j", &buf );
625  rtems_test_assert( !status );
626  dump_statbuf( &buf );
627  atime2 = buf.st_atime;
628  mtime2 = buf.st_mtime;
629  ctime2 = buf.st_ctime;
630
631
632  status = rtems_task_wake_after( rtems_clock_get_ticks_per_second() );
633  rewind( file );
634  while ( fgets(buffer, 128, file) )
635    printf( "%s", buffer );
636
637  /*
638   * Verify only atime changed for a read.
639   */
640  status = stat( "/tmp/j", &buf );
641  rtems_test_assert( !status );
642  dump_statbuf( &buf );
643  atime1 = buf.st_atime;
644  mtime1 = buf.st_mtime;
645  ctime1 = buf.st_ctime;
646  rtems_test_assert( atime1 != atime2);
647  rtems_test_assert( mtime1 == mtime2);
648  rtems_test_assert( ctime1 == ctime2);
649
650  unlink( "/tmp/joel" );
651
652  /*
653   *  Now truncate a file
654   */
655
656  status = rtems_task_wake_after( rtems_clock_get_ticks_per_second() );
657  puts( "truncate /tmp/j to length of 40" );
658  status = truncate( "/tmp/j", 40 );
659  rtems_test_assert( !status );
660
661  /*
662   * Verify truncate changed all except atime.
663   */
664  status = stat( "/tmp/j", &buf );
665  rtems_test_assert( !status );
666  dump_statbuf( &buf );
667  atime2 = buf.st_atime;
668  mtime2 = buf.st_mtime;
669  ctime2 = buf.st_ctime;
670  rtems_test_assert( atime1 == atime2);
671  rtems_test_assert( mtime1 != mtime2);
672  rtems_test_assert( ctime1 != ctime2);
673
674  /* try to truncate the console and see what happens */
675  errno = 0;
676  status = truncate( "/dev/console", 40 );
677  rtems_test_assert( status == 0 || ( status == -1 && errno == EINVAL ) );
678
679  puts( "truncate /tmp/j to length of 0" );
680  status = truncate( "/tmp/j", 0 );
681  rtems_test_assert( !status );
682
683  puts( "truncate /tmp to length of 0 should fail with EISDIR\n");
684  status = truncate( "/tmp", 0 );
685  rtems_test_assert( status == -1 );
686  printf( "%d: %s\n", errno, strerror( errno ) );
687  rtems_test_assert( errno == EISDIR );
688
689  status = truncate( "/tmp/fred", 10 );
690  rtems_test_assert( status == -1);
691
692  rtems_status = rtems_io_register_name( "/dev/not_console", 0, 0 );
693  directive_failed( rtems_status, "io register" );
694
695  test_case_reopen_append();
696
697  TEST_END();
698  rtems_test_exit( 0 );
699}
700
701/*
702 *  Open/Create a File and write to it
703 *
704 *  Test case submitted by Andrew Bythell <abythell@nortelnetworks.com>.
705 *
706 */
707
708void test_file (char *filename, char *mode);
709
710void test_case_reopen_append(void)
711{
712  printf ("Writing First File\n");
713  test_file ("/one.txt", "a");
714  test_file ("/one.txt", "a");
715
716  /* but not the second time - this will insert junk.
717     the number of ^@'s seems to equal the number of
718     actual characters in the file */
719
720  printf ("Writing Second File\n");
721  test_file ("/two.txt", "a");
722  test_file ("/two.txt", "a");
723
724  test_cat( "/one.txt", 0, 1024 );
725  test_cat( "/two.txt", 0, 1024 );
726}
727
728void test_file (char *filename, char *mode)
729{
730  FILE *fp;
731  fp = fopen (filename, mode);
732  if (!fp)
733      perror ("fopen");
734  fprintf (fp, "this is a test line\n");
735  if (fclose (fp))
736      perror ("fclose");
737}
Note: See TracBrowser for help on using the repository browser.