bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

fseek failing without fflush?


From: John W. Eaton
Subject: fseek failing without fflush?
Date: Tue, 9 Aug 2011 12:37:40 -0400

I discovered the following surprising behavior recently when adding a
few more gnulib:: namespace tags to the Octave sources.  Eventually I
was able to generate the relatively small example attached below that
shows the same behavior and is independent of Octave.

The problem seems to be that fseek is not changing the file position
at all unless I call fflush before calling fseek.  This is happening
on a newly opened file that is opened for reading only.  Perhaps I'm
missing something fundamental,  but I don't see why it should be
necessary at all, but especially not for a file opened for reading
only.

If I compile the attached program on my system (relatively recent
Debian testing, AMD64, GCC 4.6.1), without gnulib it works as I would
expect.  But with gnulib, the file position is not updated without
calls to fflush.

I'd be grateful if someone could help me understand whether this is a
bug in my code (fflush is really needed?) or if the code should be
working without having to call fflush.

I'm not sure what would be needed for someone to reproduce the
problem, so please ask for more info if it is needed.  I can send a
tarball for this minimal example made with "make dist" if that would
help.

Compiled with gnulib, the program prints the following for me when
run:

  WITHOUT flush after seek, desired position = original position = 0
  eof position = 0
  after seek to desired position = 0
  final pos after do_seek = 0
  status = 0

  WITH flush after seek, desired position = original position = 0
  eof position = 1750
  after seek to desired position = 100
  final pos after do_seek = 100
  status = 0

My bootstrap.conf, configure.ac, Makefile.am, and libgnu/Makefile.am
files are also attached below.

jwe

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <stdio.h>

long
do_tell (FILE *fptr, const char *msg)
{
  long pos = ftell (fptr);

  if (msg)
    fprintf (stderr, "%s = %ld\n", msg, pos);

  return pos;
}

int
do_seek (FILE *fptr, long offset, int origin, int flush_before_seek)
{
  if (flush_before_seek)
    fflush (fptr);

  int status = fseek (fptr, offset, origin);

  return status;
}

int
seek_within_file (FILE *fptr, long offset, int origin, int flush_before_seek)
{
  int status = -1;

  // Find current position so we can return to it if needed.

  long orig_pos = do_tell (fptr, "original position");

  // Move to end of file.  If successful, find the offset of the end.

  status = do_seek (fptr, 0, SEEK_END, flush_before_seek);

  if (status == 0)
    {
      long eof_pos = do_tell (fptr, "eof position");

      // Attempt to move to desired position; may be outside bounds of
      // existing file.

      status = do_seek (fptr, offset, origin, flush_before_seek);

      if (status == 0)
        {
          // Where are we after moving to desired position?

          long desired_pos = do_tell (fptr, "after seek to desired position");

          if (desired_pos > eof_pos || desired_pos < 0)
            {
              // The desired position is outside the bounds of the
              // existing file.  Move back to original position and
              // return failure status.

              do_seek (fptr, orig_pos, SEEK_SET, flush_before_seek);

              status = -1;
            }
        }
      else
        {
          // Seeking to the desired position failed.  Move back to
          // original position and return failure status.

          do_seek (fptr, orig_pos, SEEK_SET, flush_before_seek);

          status = -1;
        }
    }

  return status;
}

void
doit (const char *fname, long pos, int flush_before_seek, const char *msg)
{
  FILE *fptr = fopen (fname, "rb");

  fprintf (stderr, "%s, desired position = ", msg, pos);

  int status = seek_within_file (fptr, pos, SEEK_SET, flush_before_seek);

  do_tell (fptr, "final pos after do_seek");

  fprintf (stderr, "status = %d\n\n", status);

  fclose (fptr);
}

int
main (void)
{
  doit ("/etc/passwd", 100, 0, "WITHOUT flush after seek");
  doit ("/etc/passwd", 100, 1, "WITH flush after seek");

  return 0;
}
# Bootstrap configuration.

# Copyright (C) 2006-2007, 2009-2011 Free Software Foundation, Inc.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


# gnulib modules used by this package.
gnulib_modules="
  fclose
  fflush
  fopen
  fseek
  ftell
  stdio
"

# Additional xgettext options to use.  Use "\\\newline" to break lines.
XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\
 --from-code=UTF-8\\\
 --flag=asprintf:2:c-format --flag=vasprintf:2:c-format\\\
 --flag=asnprintf:3:c-format --flag=vasnprintf:3:c-format\\\
 --flag=wrapf:1:c-format\\\
'

# If "AM_GNU_GETTEXT(external" or "AM_GNU_GETTEXT([external]"
# appears in configure.ac, exclude some unnecessary files.
# Without grep's -E option (not portable enough, pre-configure),
# the following test is ugly.  Also, this depends on the existence
# of configure.ac, not the obsolescent-named configure.in.  But if
# you're using this infrastructure, you should care about such things.

gettext_external=0
grep '^[         ]*AM_GNU_GETTEXT(external\>' configure.ac > /dev/null &&
  gettext_external=1
grep '^[         ]*AM_GNU_GETTEXT(\[external\]' configure.ac > /dev/null &&
  gettext_external=1

if test $gettext_external = 1; then
  # Gettext supplies these files, but we don't need them since
  # we don't have an intl subdirectory.
  excluded_files='
      m4/glibc2.m4
      m4/intdiv0.m4
      m4/lcmessage.m4
      m4/lock.m4
      m4/printf-posix.m4
      m4/size_max.m4
      m4/uintmax_t.m4
      m4/ulonglong.m4
      m4/visibility.m4
      m4/xsize.m4
  '
fi

# Build prerequisites
buildreq="\
autoconf   2.59
automake   1.9.6
git        1.5.5
tar        -
"
checkout_only_file=HACKING
gnulib_tool_option_extras="--libtool"
gnulib_name="libgnu"
source_base="libgnu"
AC_INIT([foobar], [0.0.0])

AC_PREREQ([2.62])
AC_CONFIG_SRCDIR([foobar.c])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADER([config.h])
AM_INIT_AUTOMAKE([1.11 tar-ustar])

AC_PROG_CC
AC_PROG_CPP

gl_EARLY
gl_INIT

AC_PROG_LIBTOOL

AC_CONFIG_FILES([Makefile libgnu/Makefile])

AC_OUTPUT
EXTRA_DIST = m4/gnulib-cache.m4 HACKING AUTHORS

SUBDIRS = libgnu

AM_CPPFLAGS = -I$(top_builddir)/libgnu -I$(top_srcdir)/libgnu -I.

ACLOCAL_AMFLAGS = -I m4

foobar_SOURCES = foobar.c

foobar_LDADD = libgnu/libgnu.la

bin_PROGRAMS = foobar
include gnulib.mk

reply via email to

[Prev in Thread] Current Thread [Next in Thread]