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

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