Blame libio/tst-ftell-active-handler.c

Packit 6c4009
/* Verify that ftell returns the correct value at various points before and
Packit 6c4009
   after the handler on which it is called becomes active.
Packit 6c4009
   Copyright (C) 2014-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
#include <wchar.h>
Packit 6c4009
Packit 6c4009
static int do_test (void);
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"
Packit 6c4009
Packit 6c4009
#define get_handles_fdopen(filename, fd, fp, fd_mode, mode) \
Packit 6c4009
({									      \
Packit 6c4009
  int ret = 0;								      \
Packit 6c4009
  (fd) = open ((filename), (fd_mode), 0);				      \
Packit 6c4009
  if ((fd) == -1)							      \
Packit 6c4009
    {									      \
Packit 6c4009
      printf ("open failed: %m\n");					      \
Packit 6c4009
      ret = 1;								      \
Packit 6c4009
    }									      \
Packit 6c4009
  else									      \
Packit 6c4009
    {									      \
Packit 6c4009
      (fp) = fdopen ((fd), (mode));					      \
Packit 6c4009
      if ((fp) == NULL)							      \
Packit 6c4009
	{								      \
Packit 6c4009
	  printf ("fdopen failed: %m\n");				      \
Packit 6c4009
	  close (fd);							      \
Packit 6c4009
	  ret = 1;							      \
Packit 6c4009
	}								      \
Packit 6c4009
    }									      \
Packit 6c4009
  ret;									      \
Packit 6c4009
})
Packit 6c4009
Packit 6c4009
#define get_handles_fopen(filename, fd, fp, mode) \
Packit 6c4009
({									      \
Packit 6c4009
  int ret = 0;								      \
Packit 6c4009
  (fp) = fopen ((filename), (mode));					      \
Packit 6c4009
  if ((fp) == NULL)							      \
Packit 6c4009
    {									      \
Packit 6c4009
      printf ("fopen failed: %m\n");					      \
Packit 6c4009
      ret = 1;								      \
Packit 6c4009
    }									      \
Packit 6c4009
  else									      \
Packit 6c4009
    {									      \
Packit 6c4009
      (fd) = fileno (fp);						      \
Packit 6c4009
      if ((fd) == -1)							      \
Packit 6c4009
	{								      \
Packit 6c4009
	  printf ("fileno failed: %m\n");				      \
Packit 6c4009
	  ret = 1;							      \
Packit 6c4009
	}								      \
Packit 6c4009
    }									      \
Packit 6c4009
  ret;									      \
Packit 6c4009
})
Packit 6c4009
Packit 6c4009
/* data points to either char_data or wide_data, depending on whether we're
Packit 6c4009
   testing regular file mode or wide mode respectively.  Similarly,
Packit 6c4009
   fputs_func points to either fputs or fputws.  data_len keeps track of the
Packit 6c4009
   length of the current data and file_len maintains the current file
Packit 6c4009
   length.  */
Packit 6c4009
static const void *data;
Packit 6c4009
static const char *char_data = "abcdef";
Packit 6c4009
static const wchar_t *wide_data = L"abcdef";
Packit 6c4009
static size_t data_len;
Packit 6c4009
static size_t file_len;
Packit 6c4009
Packit 6c4009
typedef int (*fputs_func_t) (const void *data, FILE *fp);
Packit 6c4009
typedef void *(*fgets_func_t) (void *ws, int n, FILE *fp);
Packit 6c4009
fputs_func_t fputs_func;
Packit 6c4009
fgets_func_t fgets_func;
Packit 6c4009
Packit 6c4009
/* This test verifies that the offset reported by ftell is correct after the
Packit 6c4009
   file is truncated using ftruncate.  ftruncate does not change the file
Packit 6c4009
   offset on truncation and hence, SEEK_CUR should continue to point to the
Packit 6c4009
   old offset and not be changed to the new offset.  */
Packit 6c4009
static int
Packit 6c4009
do_ftruncate_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = NULL;
Packit 6c4009
  int fd;
Packit 6c4009
  int ret = 0;
Packit 6c4009
  struct test
Packit 6c4009
    {
Packit 6c4009
      const char *mode;
Packit 6c4009
      int fd_mode;
Packit 6c4009
    } test_modes[] = {
Packit 6c4009
	  {"r+", O_RDWR},
Packit 6c4009
	  {"w", O_WRONLY | O_TRUNC},
Packit 6c4009
	  {"w+", O_RDWR | O_TRUNC},
Packit 6c4009
	  {"a", O_WRONLY},
Packit 6c4009
	  {"a+", O_RDWR}
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  for (int j = 0; j < 2; j++)
Packit 6c4009
    {
Packit 6c4009
      for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
Packit 6c4009
	{
Packit 6c4009
	  int fileret;
Packit 6c4009
	  printf ("\tftruncate: %s (file, \"%s\"): ",
Packit 6c4009
		  j == 0 ? "fopen" : "fdopen",
Packit 6c4009
		  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (j == 0)
Packit 6c4009
	    fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
Packit 6c4009
	  else
Packit 6c4009
	    fileret = get_handles_fdopen (filename, fd, fp,
Packit 6c4009
					  test_modes[i].fd_mode,
Packit 6c4009
					  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (fileret != 0)
Packit 6c4009
	    return fileret;
Packit 6c4009
Packit 6c4009
	  /* Write some data.  */
Packit 6c4009
	  size_t written = fputs_func (data, fp);
Packit 6c4009
Packit 6c4009
	  if (written == EOF)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("fputs[1] failed to write data\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Record the offset.  */
Packit 6c4009
	  long offset = ftell (fp);
Packit 6c4009
Packit 6c4009
	  /* Flush data to allow switching active handles.  */
Packit 6c4009
	  if (fflush (fp))
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Flush failed: %m\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Now truncate the file.  */
Packit 6c4009
	  if (ftruncate (fd, 0) != 0)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Failed to truncate file: %m\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* ftruncate does not change the offset, so there is no need to call
Packit 6c4009
	     anything to be able to switch active handles.  */
Packit 6c4009
	  long new_offset = ftell (fp);
Packit 6c4009
Packit 6c4009
	  /* The offset should remain unchanged since ftruncate does not update
Packit 6c4009
	     it.  */
Packit 6c4009
	  if (offset != new_offset)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect offset.  Expected %ld, but got %ld\n",
Packit 6c4009
		      offset, new_offset);
Packit 6c4009
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    printf ("offset = %ld\n", offset);
Packit 6c4009
Packit 6c4009
	  fclose (fp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
/* Test that ftell output after a rewind is correct.  */
Packit 6c4009
static int
Packit 6c4009
do_rewind_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  int ret = 0;
Packit 6c4009
  struct test
Packit 6c4009
    {
Packit 6c4009
      const char *mode;
Packit 6c4009
      int fd_mode;
Packit 6c4009
      size_t old_off;
Packit 6c4009
      size_t new_off;
Packit 6c4009
    } test_modes[] = {
Packit 6c4009
	  {"w", O_WRONLY | O_TRUNC, 0, data_len},
Packit 6c4009
	  {"w+", O_RDWR | O_TRUNC, 0, data_len},
Packit 6c4009
	  {"r+", O_RDWR, 0, data_len},
Packit 6c4009
	  /* The new offsets for 'a' and 'a+' modes have to factor in the
Packit 6c4009
	     previous writes since they always append to the end of the
Packit 6c4009
	     file.  */
Packit 6c4009
	  {"a", O_WRONLY, 0, 3 * data_len},
Packit 6c4009
	  {"a+", O_RDWR, 0, 4 * data_len},
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  /* Empty the file before the test so that our offsets are simple to
Packit 6c4009
     calculate.  */
Packit 6c4009
  FILE *fp = fopen (filename, "w");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("Failed to open file for emptying\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  fclose (fp);
Packit 6c4009
Packit 6c4009
  for (int j = 0; j < 2; j++)
Packit 6c4009
    {
Packit 6c4009
      for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
Packit 6c4009
	{
Packit 6c4009
	  FILE *fp;
Packit 6c4009
	  int fd;
Packit 6c4009
	  int fileret;
Packit 6c4009
Packit 6c4009
	  printf ("\trewind: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen",
Packit 6c4009
		  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (j == 0)
Packit 6c4009
	    fileret = get_handles_fdopen (filename, fd, fp,
Packit 6c4009
					  test_modes[i].fd_mode,
Packit 6c4009
					  test_modes[i].mode);
Packit 6c4009
	  else
Packit 6c4009
	    fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (fileret != 0)
Packit 6c4009
	    return fileret;
Packit 6c4009
Packit 6c4009
	  /* Write some content to the file, rewind and ensure that the ftell
Packit 6c4009
	     output after the rewind is 0.  POSIX does not specify what the
Packit 6c4009
	     behavior is when a file is rewound in 'a' mode, so we retain
Packit 6c4009
	     current behavior, which is to keep the 0 offset.  */
Packit 6c4009
	  size_t written = fputs_func (data, fp);
Packit 6c4009
Packit 6c4009
	  if (written == EOF)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("fputs[1] failed to write data\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  rewind (fp);
Packit 6c4009
	  long offset = ftell (fp);
Packit 6c4009
Packit 6c4009
	  if (offset != test_modes[i].old_off)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect old offset.  Expected %zu, but got %ld, ",
Packit 6c4009
		      test_modes[i].old_off, offset);
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    printf ("old offset = %ld, ", offset);
Packit 6c4009
Packit 6c4009
	  written = fputs_func (data, fp);
Packit 6c4009
Packit 6c4009
	  if (written == EOF)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("fputs[1] failed to write data\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* After this write, the offset in append modes should factor in the
Packit 6c4009
	     implicit lseek to the end of file.  */
Packit 6c4009
	  offset = ftell (fp);
Packit 6c4009
	  if (offset != test_modes[i].new_off)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect new offset.  Expected %zu, but got %ld\n",
Packit 6c4009
		      test_modes[i].new_off, offset);
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    printf ("new offset = %ld\n", offset);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Test that the value of ftell is not cached when the stream handle is not
Packit 6c4009
   active.  */
Packit 6c4009
static int
Packit 6c4009
do_ftell_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  int ret = 0;
Packit 6c4009
  struct test
Packit 6c4009
    {
Packit 6c4009
      const char *mode;
Packit 6c4009
      int fd_mode;
Packit 6c4009
      size_t old_off;
Packit 6c4009
      size_t new_off;
Packit 6c4009
      size_t eof_off;
Packit 6c4009
    } test_modes[] = {
Packit 6c4009
	  /* In w, w+ and r+ modes, the file position should be at the
Packit 6c4009
	     beginning of the file.  After the write, the offset should be
Packit 6c4009
	     updated to data_len.  We don't use eof_off in w and a modes since
Packit 6c4009
	     they don't allow reading.  */
Packit 6c4009
	  {"w", O_WRONLY | O_TRUNC, 0, data_len, 0},
Packit 6c4009
	  {"w+", O_RDWR | O_TRUNC, 0, data_len, 2 * data_len},
Packit 6c4009
	  {"r+", O_RDWR, 0, data_len, 3 * data_len},
Packit 6c4009
	  /* For the 'a' mode, the initial file position should be the
Packit 6c4009
	     current end of file. After the write, the offset has data_len
Packit 6c4009
	     added to the old value.  For a+ mode however, the initial file
Packit 6c4009
	     position is the file position of the underlying file descriptor,
Packit 6c4009
	     since it is initially assumed to be in read mode.  */
Packit 6c4009
	  {"a", O_WRONLY, 3 * data_len, 4 * data_len, 5 * data_len},
Packit 6c4009
	  {"a+", O_RDWR, 0, 5 * data_len, 6 * data_len},
Packit 6c4009
    };
Packit 6c4009
  for (int j = 0; j < 2; j++)
Packit 6c4009
    {
Packit 6c4009
      for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
Packit 6c4009
	{
Packit 6c4009
	  FILE *fp;
Packit 6c4009
	  int fd;
Packit 6c4009
	  int fileret;
Packit 6c4009
Packit 6c4009
	  printf ("\tftell: %s (file, \"%s\"): ", j == 0 ? "fdopen" : "fopen",
Packit 6c4009
		  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (j == 0)
Packit 6c4009
	    fileret = get_handles_fdopen (filename, fd, fp,
Packit 6c4009
					  test_modes[i].fd_mode,
Packit 6c4009
					  test_modes[i].mode);
Packit 6c4009
	  else
Packit 6c4009
	    fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (fileret != 0)
Packit 6c4009
	    return fileret;
Packit 6c4009
Packit 6c4009
	  long off = ftell (fp);
Packit 6c4009
	  if (off != test_modes[i].old_off)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect old offset.  Expected %zu but got %ld, ",
Packit 6c4009
		      test_modes[i].old_off, off);
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    printf ("old offset = %ld, ", off);
Packit 6c4009
Packit 6c4009
	  /* The effect of this write on the offset should be seen in the ftell
Packit 6c4009
	     call that follows it.  */
Packit 6c4009
	  int write_ret = write (fd, data, data_len);
Packit 6c4009
	  if (write_ret != data_len)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("write failed (%m)\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  off = ftell (fp);
Packit 6c4009
Packit 6c4009
	  if (off != test_modes[i].new_off)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect new offset.  Expected %zu but got %ld",
Packit 6c4009
		      test_modes[i].new_off, off);
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    printf ("new offset = %ld", off);
Packit 6c4009
Packit 6c4009
	  /* Read to the end, write some data to the fd and check if ftell can
Packit 6c4009
	     see the new ofset.  Do this test only for files that allow
Packit 6c4009
	     reading.  */
Packit 6c4009
	  if (test_modes[i].fd_mode != O_WRONLY)
Packit 6c4009
	    {
Packit 6c4009
	      wchar_t tmpbuf[data_len];
Packit 6c4009
Packit 6c4009
	      rewind (fp);
Packit 6c4009
Packit 6c4009
	      while (fgets_func (tmpbuf, data_len, fp) && !feof (fp));
Packit 6c4009
Packit 6c4009
	      write_ret = write (fd, data, data_len);
Packit 6c4009
	      if (write_ret != data_len)
Packit 6c4009
		{
Packit 6c4009
		  printf ("write failed (%m)\n");
Packit 6c4009
		  ret |= 1;
Packit 6c4009
		}
Packit 6c4009
	      off = ftell (fp);
Packit 6c4009
Packit 6c4009
	      if (off != test_modes[i].eof_off)
Packit 6c4009
		{
Packit 6c4009
		  printf (", Incorrect offset after read EOF.  "
Packit 6c4009
			  "Expected %zu but got %ld\n",
Packit 6c4009
			  test_modes[i].eof_off, off);
Packit 6c4009
		  ret |= 1;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		printf (", offset after EOF = %ld\n", off);
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    putc ('\n', stdout);
Packit 6c4009
Packit 6c4009
	  fclose (fp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This test opens the file for writing, moves the file offset of the
Packit 6c4009
   underlying file, writes out data and then checks if ftell trips on it.  */
Packit 6c4009
static int
Packit 6c4009
do_write_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = NULL;
Packit 6c4009
  int fd;
Packit 6c4009
  int ret = 0;
Packit 6c4009
  struct test
Packit 6c4009
    {
Packit 6c4009
      const char *mode;
Packit 6c4009
      int fd_mode;
Packit 6c4009
    } test_modes[] = {
Packit 6c4009
	  {"w", O_WRONLY | O_TRUNC},
Packit 6c4009
	  {"w+", O_RDWR | O_TRUNC},
Packit 6c4009
	  {"r+", O_RDWR}
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  for (int j = 0; j < 2; j++)
Packit 6c4009
    {
Packit 6c4009
      for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
Packit 6c4009
	{
Packit 6c4009
	  int fileret;
Packit 6c4009
	  printf ("\twrite: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen",
Packit 6c4009
		  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (j == 0)
Packit 6c4009
	    fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
Packit 6c4009
	  else
Packit 6c4009
	    fileret = get_handles_fdopen (filename, fd, fp,
Packit 6c4009
					  test_modes[i].fd_mode,
Packit 6c4009
					  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (fileret != 0)
Packit 6c4009
	    return fileret;
Packit 6c4009
Packit 6c4009
	  /* Move offset to just before the end of the file.  */
Packit 6c4009
	  off_t seek_ret = lseek (fd, file_len - 1, SEEK_SET);
Packit 6c4009
	  if (seek_ret == -1)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("lseek failed: %m\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Write some data.  */
Packit 6c4009
	  size_t written = fputs_func (data, fp);
Packit 6c4009
Packit 6c4009
	  if (written == EOF)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("fputs[1] failed to write data\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Verify that the offset points to the end of the file.  The length
Packit 6c4009
	     of the file would be the original length + the length of data
Packit 6c4009
	     written to it - the amount by which we moved the offset using
Packit 6c4009
	     lseek.  */
Packit 6c4009
	  long offset = ftell (fp);
Packit 6c4009
	  file_len = file_len - 1 + data_len;
Packit 6c4009
Packit 6c4009
	  if (offset != file_len)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect offset.  Expected %zu, but got %ld\n",
Packit 6c4009
		      file_len, offset);
Packit 6c4009
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  printf ("offset = %ld\n", offset);
Packit 6c4009
	  fclose (fp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This test opens a file in append mode, writes some data, and then verifies
Packit 6c4009
   that ftell does not trip over it.  */
Packit 6c4009
static int
Packit 6c4009
do_append_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  FILE *fp = NULL;
Packit 6c4009
  int ret = 0;
Packit 6c4009
  int fd;
Packit 6c4009
Packit 6c4009
  struct test
Packit 6c4009
    {
Packit 6c4009
      const char *mode;
Packit 6c4009
      int fd_mode;
Packit 6c4009
    } test_modes[] = {
Packit 6c4009
	  {"a", O_WRONLY},
Packit 6c4009
	  {"a+", O_RDWR}
Packit 6c4009
    };
Packit 6c4009
Packit 6c4009
  for (int j = 0; j < 2; j++)
Packit 6c4009
    {
Packit 6c4009
      for (int i = 0; i < sizeof (test_modes) / sizeof (struct test); i++)
Packit 6c4009
	{
Packit 6c4009
	  int fileret;
Packit 6c4009
Packit 6c4009
	  printf ("\tappend: %s (file, \"%s\"): ", j == 0 ? "fopen" : "fdopen",
Packit 6c4009
		  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (j == 0)
Packit 6c4009
	    fileret = get_handles_fopen (filename, fd, fp, test_modes[i].mode);
Packit 6c4009
	  else
Packit 6c4009
	    fileret = get_handles_fdopen (filename, fd, fp,
Packit 6c4009
					  test_modes[i].fd_mode,
Packit 6c4009
					  test_modes[i].mode);
Packit 6c4009
Packit 6c4009
	  if (fileret != 0)
Packit 6c4009
	    return fileret;
Packit 6c4009
Packit 6c4009
	  /* Write some data.  */
Packit 6c4009
	  size_t written = fputs_func (data, fp);
Packit 6c4009
Packit 6c4009
	  if (written == EOF)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("fputs[1] failed to write all data\n");
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Verify that the offset points to the end of the file.  The file
Packit 6c4009
	     len is maintained by adding data_len each time to reflect the data
Packit 6c4009
	     written to it.  */
Packit 6c4009
	  long offset = ftell (fp);
Packit 6c4009
	  file_len += data_len;
Packit 6c4009
Packit 6c4009
	  if (offset != file_len)
Packit 6c4009
	    {
Packit 6c4009
	      printf ("Incorrect offset.  Expected %zu, but got %ld\n",
Packit 6c4009
		      file_len, offset);
Packit 6c4009
Packit 6c4009
	      ret |= 1;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  printf ("offset = %ld\n", offset);
Packit 6c4009
	  fclose (fp);
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* For fdopen in 'a' mode, the file descriptor should not change if the file
Packit 6c4009
     is already open with the O_APPEND flag set.  */
Packit 6c4009
  fd = open (filename, O_WRONLY | O_APPEND, 0);
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    {
Packit 6c4009
      printf ("open(O_APPEND) failed: %m\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  off_t seek_ret = lseek (fd, file_len - 1, SEEK_SET);
Packit 6c4009
  if (seek_ret == -1)
Packit 6c4009
    {
Packit 6c4009
      printf ("lseek[O_APPEND][0] failed: %m\n");
Packit 6c4009
      ret |= 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fp = fdopen (fd, "a");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("fdopen(O_APPEND) failed: %m\n");
Packit 6c4009
      close (fd);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  off_t new_seek_ret = lseek (fd, 0, SEEK_CUR);
Packit 6c4009
  if (seek_ret == -1)
Packit 6c4009
    {
Packit 6c4009
      printf ("lseek[O_APPEND][1] failed: %m\n");
Packit 6c4009
      ret |= 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  printf ("\tappend: fdopen (file, \"a\"): O_APPEND: ");
Packit 6c4009
Packit 6c4009
  if (seek_ret != new_seek_ret)
Packit 6c4009
    {
Packit 6c4009
      printf ("incorrectly modified file offset to %jd, should be %jd",
Packit 6c4009
	      (intmax_t)  new_seek_ret, (intmax_t) seek_ret);
Packit 6c4009
      ret |= 1;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    printf ("retained current file offset %jd", (intmax_t) seek_ret);
Packit 6c4009
Packit 6c4009
  new_seek_ret = ftello (fp);
Packit 6c4009
Packit 6c4009
  if (seek_ret != new_seek_ret)
Packit 6c4009
    {
Packit 6c4009
      printf (", ftello reported incorrect offset %jd, should be %jd\n",
Packit 6c4009
	      (intmax_t) new_seek_ret, (intmax_t) seek_ret);
Packit 6c4009
      ret |= 1;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    printf (", ftello reported correct offset %jd\n", (intmax_t) seek_ret);
Packit 6c4009
Packit 6c4009
  fclose (fp);
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_one_test (const char *filename)
Packit 6c4009
{
Packit 6c4009
  int ret = 0;
Packit 6c4009
Packit 6c4009
  ret |= do_ftell_test (filename);
Packit 6c4009
  ret |= do_write_test (filename);
Packit 6c4009
  ret |= do_append_test (filename);
Packit 6c4009
  ret |= do_rewind_test (filename);
Packit 6c4009
  ret |= do_ftruncate_test (filename);
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Run a set of tests for ftell for regular files and wide mode files.  */
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  int ret = 0;
Packit 6c4009
  FILE *fp = NULL;
Packit 6c4009
  char *filename;
Packit 6c4009
  size_t written;
Packit 6c4009
  int fd = create_temp_file ("tst-active-handler-tmp.", &filename);
Packit 6c4009
Packit 6c4009
  if (fd == -1)
Packit 6c4009
    {
Packit 6c4009
      printf ("create_temp_file: %m\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fp = fdopen (fd, "w");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("fdopen[0]: %m\n");
Packit 6c4009
      close (fd);
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  data = char_data;
Packit 6c4009
  data_len = strlen (char_data);
Packit 6c4009
  file_len = strlen (char_data);
Packit 6c4009
  written = fputs (data, fp);
Packit 6c4009
Packit 6c4009
  if (written == EOF)
Packit 6c4009
    {
Packit 6c4009
      printf ("fputs[1] failed to write data\n");
Packit 6c4009
      ret = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  fclose (fp);
Packit 6c4009
  if (ret)
Packit 6c4009
    return ret;
Packit 6c4009
Packit 6c4009
  /* Tests for regular files.  */
Packit 6c4009
  puts ("Regular mode:");
Packit 6c4009
  fputs_func = (fputs_func_t) fputs;
Packit 6c4009
  fgets_func = (fgets_func_t) fgets;
Packit 6c4009
  data = char_data;
Packit 6c4009
  data_len = strlen (char_data);
Packit 6c4009
  ret |= do_one_test (filename);
Packit 6c4009
Packit 6c4009
  /* Truncate the file before repeating the tests in wide mode.  */
Packit 6c4009
  fp = fopen (filename, "w");
Packit 6c4009
  if (fp == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("fopen failed %m\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  fclose (fp);
Packit 6c4009
Packit 6c4009
  /* Tests for wide files.  */
Packit 6c4009
  puts ("Wide mode:");
Packit 6c4009
  if (setlocale (LC_ALL, "en_US.UTF-8") == NULL)
Packit 6c4009
    {
Packit 6c4009
      printf ("Cannot set en_US.UTF-8 locale.\n");
Packit 6c4009
      return 1;
Packit 6c4009
    }
Packit 6c4009
  fputs_func = (fputs_func_t) fputws;
Packit 6c4009
  fgets_func = (fgets_func_t) fgetws;
Packit 6c4009
  data = wide_data;
Packit 6c4009
  data_len = wcslen (wide_data);
Packit 6c4009
  ret |= do_one_test (filename);
Packit 6c4009
Packit 6c4009
  return ret;
Packit 6c4009
}