Blame lib/close-stream.c

Packit 709fb3
/* Close a stream, with nicer error checking than fclose's.
Packit 709fb3
Packit 709fb3
   Copyright (C) 1998-2002, 2004, 2006-2017 Free Software Foundation, Inc.
Packit 709fb3
Packit 709fb3
   This program is free software: you can redistribute it and/or modify
Packit 709fb3
   it under the terms of the GNU General Public License as published by
Packit 709fb3
   the Free Software Foundation; either version 3 of the License, or
Packit 709fb3
   (at your option) any later version.
Packit 709fb3
Packit 709fb3
   This program is distributed in the hope that it will be useful,
Packit 709fb3
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 709fb3
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 709fb3
   GNU General Public License for more details.
Packit 709fb3
Packit 709fb3
   You should have received a copy of the GNU General Public License
Packit 709fb3
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 709fb3
Packit 709fb3
#include <config.h>
Packit 709fb3
Packit 709fb3
#include "close-stream.h"
Packit 709fb3
Packit 709fb3
#include <errno.h>
Packit 709fb3
#include <stdbool.h>
Packit 709fb3
Packit 709fb3
#include "fpending.h"
Packit 709fb3
Packit 709fb3
#if USE_UNLOCKED_IO
Packit 709fb3
# include "unlocked-io.h"
Packit 709fb3
#endif
Packit 709fb3
Packit 709fb3
/* Close STREAM.  Return 0 if successful, EOF (setting errno)
Packit 709fb3
   otherwise.  A failure might set errno to 0 if the error number
Packit 709fb3
   cannot be determined.
Packit 709fb3
Packit 709fb3
   A failure with errno set to EPIPE may or may not indicate an error
Packit 709fb3
   situation worth signaling to the user.  See the documentation of the
Packit 709fb3
   close_stdout_set_ignore_EPIPE function for details.
Packit 709fb3
Packit 709fb3
   If a program writes *anything* to STREAM, that program should close
Packit 709fb3
   STREAM and make sure that it succeeds before exiting.  Otherwise,
Packit 709fb3
   suppose that you go to the extreme of checking the return status
Packit 709fb3
   of every function that does an explicit write to STREAM.  The last
Packit 709fb3
   printf can succeed in writing to the internal stream buffer, and yet
Packit 709fb3
   the fclose(STREAM) could still fail (due e.g., to a disk full error)
Packit 709fb3
   when it tries to write out that buffered data.  Thus, you would be
Packit 709fb3
   left with an incomplete output file and the offending program would
Packit 709fb3
   exit successfully.  Even calling fflush is not always sufficient,
Packit 709fb3
   since some file systems (NFS and CODA) buffer written/flushed data
Packit 709fb3
   until an actual close call.
Packit 709fb3
Packit 709fb3
   Besides, it's wasteful to check the return value from every call
Packit 709fb3
   that writes to STREAM -- just let the internal stream state record
Packit 709fb3
   the failure.  That's what the ferror test is checking below.  */
Packit 709fb3
Packit 709fb3
int
Packit 709fb3
close_stream (FILE *stream)
Packit 709fb3
{
Packit 709fb3
  const bool some_pending = (__fpending (stream) != 0);
Packit 709fb3
  const bool prev_fail = (ferror (stream) != 0);
Packit 709fb3
  const bool fclose_fail = (fclose (stream) != 0);
Packit 709fb3
Packit 709fb3
  /* Return an error indication if there was a previous failure or if
Packit 709fb3
     fclose failed, with one exception: ignore an fclose failure if
Packit 709fb3
     there was no previous error, no data remains to be flushed, and
Packit 709fb3
     fclose failed with EBADF.  That can happen when a program like cp
Packit 709fb3
     is invoked like this 'cp a b >&-' (i.e., with standard output
Packit 709fb3
     closed) and doesn't generate any output (hence no previous error
Packit 709fb3
     and nothing to be flushed).  */
Packit 709fb3
Packit 709fb3
  if (prev_fail || (fclose_fail && (some_pending || errno != EBADF)))
Packit 709fb3
    {
Packit 709fb3
      if (! fclose_fail)
Packit 709fb3
        errno = 0;
Packit 709fb3
      return EOF;
Packit 709fb3
    }
Packit 709fb3
Packit 709fb3
  return 0;
Packit 709fb3
}