Imported Upstream version 1.5
[debian/gzip] / lib / fclose.c
index 9f4388912aa093acca36473478594668159bd381..e9986ca53f18f76ac2d62e4ef8dcd37a39f08518 100644 (file)
@@ -1,5 +1,5 @@
 /* fclose replacement.
-   Copyright (C) 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 2008-2012 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
 #include <errno.h>
 #include <unistd.h>
 
-/* Override fclose() to call the overridden close().  */
+#include "freading.h"
+#include "msvc-inval.h"
+
+#undef fclose
+
+#if HAVE_MSVC_INVALID_PARAMETER_HANDLER
+static int
+fclose_nothrow (FILE *fp)
+{
+  int result;
+
+  TRY_MSVC_INVAL
+    {
+      result = fclose (fp);
+    }
+  CATCH_MSVC_INVAL
+    {
+      result = EOF;
+      errno = EBADF;
+    }
+  DONE_MSVC_INVAL;
+
+  return result;
+}
+#else
+# define fclose_nothrow fclose
+#endif
+
+/* Override fclose() to call the overridden fflush() or close().  */
 
 int
 rpl_fclose (FILE *fp)
-#undef fclose
 {
   int saved_errno = 0;
+  int fd;
+  int result = 0;
+
+  /* Don't change behavior on memstreams.  */
+  fd = fileno (fp);
+  if (fd < 0)
+    return fclose_nothrow (fp);
 
-  if (fflush (fp))
+  /* We only need to flush the file if it is not reading or if it is
+     seekable.  This only guarantees the file position of input files
+     if the fflush module is also in use.  */
+  if ((!freading (fp) || lseek (fileno (fp), 0, SEEK_CUR) != -1)
+      && fflush (fp))
     saved_errno = errno;
 
-  if (close (fileno (fp)) < 0 && saved_errno == 0)
+  /* fclose() calls close(), but we need to also invoke all hooks that our
+     overridden close() function invokes.  See lib/close.c.  */
+#if WINDOWS_SOCKETS
+  /* Call the overridden close(), then the original fclose().
+     Note about multithread-safety: There is a race condition where some
+     other thread could open fd between our close and fclose.  */
+  if (close (fd) < 0 && saved_errno == 0)
     saved_errno = errno;
 
-  fclose (fp); /* will fail with errno = EBADF */
+  fclose_nothrow (fp); /* will fail with errno = EBADF,
+                          if we did not lose a race */
+
+#else /* !WINDOWS_SOCKETS */
+  /* Call fclose() and invoke all hooks of the overridden close().  */
+
+# if REPLACE_FCHDIR
+  /* Note about multithread-safety: There is a race condition here as well.
+     Some other thread could open fd between our calls to fclose and
+     _gl_unregister_fd.  */
+  result = fclose_nothrow (fp);
+  if (result == 0)
+    _gl_unregister_fd (fd);
+# else
+  /* No race condition here.  */
+  result = fclose_nothrow (fp);
+# endif
+
+#endif /* !WINDOWS_SOCKETS */
 
   if (saved_errno != 0)
     {
       errno = saved_errno;
-      return EOF;
+      result = EOF;
     }
-  return 0;
+
+  return result;
 }