From 2d6ba0f9d34196be6726f55eb24cad2e5a877727 Mon Sep 17 00:00:00 2001
From: pbrook <pbrook@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Sat, 22 Jan 2005 19:49:18 +0000
Subject: [PATCH] 2005-01-22  Thomas Koenig  <Thomas.Koenig@online.de>

	PR libfortran/18982
	* io/unix.c (regular_file):  No need to change flags->action
	if an error occurs.  Document this.
	No need to call stat() for STATUS_OLD, open() will
	fail anyway.
	For ACTION_UNSPECIFIED, try open for read-write, then for
	read-only if open fails with EACCES, then for write-only
	if that fails with EACCES again.
	* io/unix.c (open_external): Document changed behavior of
	regular_file.
testsuite/
	* gfortran.dg/open_new.f90: New file.


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@94076 138bc75d-0d04-0410-961f-82ee72b054a4
---
 gcc/testsuite/ChangeLog                |  5 ++
 gcc/testsuite/gfortran.dg/open_new.f90 | 11 ++++
 libgfortran/ChangeLog                  | 13 +++++
 libgfortran/io/unix.c                  | 71 +++++++++++++++-----------
 4 files changed, 70 insertions(+), 30 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/open_new.f90

diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7115b358a4bd..b39fb693f0c7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2005-01-22  Thomas Koenig  <Thomas.Koenig@online.de>
+
+	PR libfortran/18982
+	* gfortran.dg/open_new.f90: New file.
+
 2005-01-22  Paul Brook  <paul@codesourcery.com>
 
 	* namelist_1.f90: New test.
diff --git a/gcc/testsuite/gfortran.dg/open_new.f90 b/gcc/testsuite/gfortran.dg/open_new.f90
new file mode 100644
index 000000000000..9e9c95127769
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/open_new.f90
@@ -0,0 +1,11 @@
+! { dg do-run }
+! PR 18982:  verifies that opening an existing file with
+!            status="new" is an error
+program main
+  nout = 10
+  open(nout, file="foo.dat", status="replace")     ! make sure foo.dat exists
+  close(nout)
+  open(nout, file="foo.dat", status="new",err=100)
+  call abort                 ! This should never happen
+100 continue
+end program main
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 95242b6396bd..537415f16fe6 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,16 @@
+2005-01-22  Thomas Koenig  <Thomas.Koenig@online.de>
+
+	PR libfortran/18982
+	* io/unix.c (regular_file):  No need to change flags->action
+	if an error occurs.  Document this.  
+	No need to call stat() for STATUS_OLD, open() will
+	fail anyway.
+	For ACTION_UNSPECIFIED, try open for read-write, then for
+	read-only if open fails with EACCES, then for write-only
+	if that fails with EACCES again.
+	* io/unix.c (open_external): Document changed behavior of
+	regular_file.
+
 2005-01-22  Tobias Schl"uter  <tobias.schlueter@physik.uni-muenchen.de>
 	
 	PR fortran/19194
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index e174e3be9ca8..daa0fb110726 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -998,16 +998,17 @@ tempfile (void)
 
 
 /* regular_file()-- Open a regular file.
- * Change flags->action if it is ACTION_UNSPECIFIED on entry.
+ * Change flags->action if it is ACTION_UNSPECIFIED on entry,
+ * unless an error occurs.
  * Returns the descriptor, which is less than zero on error. */
 
 static int
 regular_file (unit_flags *flags)
 {
   char path[PATH_MAX + 1];
-  struct stat statbuf;
   int mode;
   int rwflag;
+  int crflag;
   int fd;
 
   if (unpack_filename (path, ioparm.file, ioparm.file_len))
@@ -1040,21 +1041,20 @@ regular_file (unit_flags *flags)
   switch (flags->status)
     {
     case STATUS_NEW:
-      rwflag |= O_CREAT | O_EXCL;
+      crflag = O_CREAT | O_EXCL;
       break;
 
-    case STATUS_OLD:		/* file must exist, so check for its existence */
-      if (stat (path, &statbuf) < 0)
-	return -1;
+    case STATUS_OLD:		/* open will fail if the file does not exist*/
+      crflag = 0;
       break;
 
     case STATUS_UNKNOWN:
     case STATUS_SCRATCH:
-      rwflag |= O_CREAT;
+      crflag = O_CREAT;
       break;
 
     case STATUS_REPLACE:
-        rwflag |= O_CREAT | O_TRUNC;
+        crflag = O_CREAT | O_TRUNC;
       break;
 
     default:
@@ -1064,29 +1064,39 @@ regular_file (unit_flags *flags)
   /* rwflag |= O_LARGEFILE; */
 
   mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
-  fd = open (path, rwflag, mode);
-  if (flags->action == ACTION_UNSPECIFIED)
+  fd = open (path, rwflag | crflag, mode);
+  if (flags->action != ACTION_UNSPECIFIED)
+      return fd;
+
+  if (fd >= 0)
     {
-      if (fd < 0)
-        {
-          rwflag = rwflag & !O_RDWR | O_RDONLY;
-          fd = open (path, rwflag, mode);
-          if (fd < 0)
-            {
-	      rwflag = rwflag & !O_RDONLY | O_WRONLY;
-              fd = open (path, rwflag, mode);
-              if (fd < 0)
-                flags->action = ACTION_READWRITE; /* Could not open at all.  */
-              else
-                flags->action = ACTION_WRITE;
-            }
-          else
-            flags->action = ACTION_READ;
-        }
-      else
-        flags->action = ACTION_READWRITE;
+      flags->action = ACTION_READWRITE;
+      return fd;
     }
-  return fd;
+  if (errno != EACCES)
+     return fd;
+
+  /* retry for read-only access */
+  rwflag = O_RDONLY;
+  fd = open (path, rwflag | crflag, mode);
+  if (fd >=0)
+    {
+      flags->action = ACTION_READ;
+      return fd;               /* success */
+    }
+  
+  if (errno != EACCES)
+    return fd;                 /* failure */
+
+  /* retry for write-only access */
+  rwflag = O_WRONLY;
+  fd = open (path, rwflag | crflag, mode);
+  if (fd >=0)
+    {
+      flags->action = ACTION_WRITE;
+      return fd;               /* success */
+    }
+  return fd;                   /* failure */
 }
 
 
@@ -1109,7 +1119,8 @@ open_external (unit_flags *flags)
     }
   else
     {
-      /* regular_file resets flags->action if it is ACTION_UNSPECIFIED.  */
+      /* regular_file resets flags->action if it is ACTION_UNSPECIFIED and
+       * if it succeeds */
       fd = regular_file (flags);
     }
 
-- 
GitLab