From c8f077d42bbd594ec1e2f19f09b6e24364d4e8b4 Mon Sep 17 00:00:00 2001
From: sof <unknown>
Date: Thu, 4 Feb 1999 12:13:16 +0000
Subject: [PATCH] [project @ 1999-02-04 12:13:15 by sof] - relax the
 restriction that just the one open writeable handle on   *the same file* may
 exist when dealing with the standard handles,   stdout and stderr.

  Reason: the following invocation of a Haskell program,

      foo >log 2>&1

  should be acceptable.
---
 ghc/lib/std/cbits/getLock.c  | 76 ++++++++++++++++++++++++------------
 ghc/lib/std/cbits/openFile.c | 26 +++++++-----
 ghc/lib/std/cbits/stgio.h    |  4 +-
 3 files changed, 70 insertions(+), 36 deletions(-)

diff --git a/ghc/lib/std/cbits/getLock.c b/ghc/lib/std/cbits/getLock.c
index a0d93adf7f3a..be6acb46f159 100644
--- a/ghc/lib/std/cbits/getLock.c
+++ b/ghc/lib/std/cbits/getLock.c
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: getLock.c,v 1.3 1998/12/02 13:27:41 simonm Exp $
+ * $Id: getLock.c,v 1.4 1999/02/04 12:13:15 sof Exp $
  *
  * stdin/stout/stderr Runtime Support
  */
@@ -42,8 +42,9 @@ static int readLocks = 0;
 static int writeLocks = 0;
 
 int
-lockFile(fd, exclusive)
+lockFile(fd, for_writing, exclusive)
 int fd;
+int for_writing;
 int exclusive;
 {
     int i;
@@ -59,31 +60,55 @@ int exclusive;
     if (!S_ISREG(sb.st_mode))
 	return 0;
     
-    for (i = 0; i < writeLocks; i++)
-	if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
+    if (for_writing) {
+      /* opening a file for writing, check to see whether
+         we don't have any read locks on it already.. */
+      for (i = 0; i < readLocks; i++) {
+	 if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
 	    errno = EAGAIN;
 	    return -1;
-	}
-
-    if (!exclusive) {
-	i = readLocks++;
-	readLock[i].device = sb.st_dev;
-	readLock[i].inode = sb.st_ino;
-	readLock[i].fd = fd;
-	return 0;
-    }
-
-    for (i = 0; i < readLocks; i++)
-	if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
+	 }	    
+      }
+      /* If we're determined that there is only a single
+         writer to the file, check to see whether the file
+	 hasn't already been opened for writing..
+      */
+      if (exclusive) {
+	for (i = 0; i < writeLocks; i++) {
+	  if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
+	     errno = EAGAIN;
+	     return -1;
+	  }
+        }
+      }
+      /* OK, everything is cool lock-wise, record it and leave. */
+      i = writeLocks++;
+      writeLock[i].device = sb.st_dev;
+      writeLock[i].inode = sb.st_ino;
+      writeLock[i].fd = fd;
+      return 0;
+    } else { 
+      /* For reading, it's simpler - just check to see
+         that there's no-one writing to the underlying file. */
+      for (i = 0; i < writeLocks; i++) {
+	if (writeLock[i].inode == sb.st_ino && writeLock[i].device == sb.st_dev) {
 	    errno = EAGAIN;
 	    return -1;
-	}	    
+        }
+      }
+      /* Fit in new entry, reusing an existing table entry, if possible. */
+      for (i = 0; i < readLocks; i++) {
+	 if (readLock[i].inode == sb.st_ino && readLock[i].device == sb.st_dev) {
+	   return 0;
+	 }
+      }
+      i = readLocks++;
+      readLock[i].device = sb.st_dev;
+      readLock[i].inode = sb.st_ino;
+      readLock[i].fd = fd;
+      return 0;
+    }
 
-    i = writeLocks++;
-    writeLock[i].device = sb.st_dev;
-    writeLock[i].inode = sb.st_ino;
-    writeLock[i].fd = fd;
-    return 0;
 }
 
 int
@@ -111,12 +136,13 @@ int fd;
     return 1;
 }
 
+/* getLock() is used when opening the standard file descriptors */
 StgInt
-getLock(fd, exclusive)
+getLock(fd, for_writing)
 StgInt fd;
-StgInt exclusive;
+StgInt for_writing;
 {
-    if (lockFile(fd, exclusive) < 0) {
+    if (lockFile(fd, for_writing, 0) < 0) {
 	if (errno == EBADF)
 	    return 0;
 	else {
diff --git a/ghc/lib/std/cbits/openFile.c b/ghc/lib/std/cbits/openFile.c
index 2d5afe516b53..7d3b217ad2f3 100644
--- a/ghc/lib/std/cbits/openFile.c
+++ b/ghc/lib/std/cbits/openFile.c
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: openFile.c,v 1.5 1999/01/23 17:44:40 sof Exp $
+ * $Id: openFile.c,v 1.6 1999/02/04 12:13:15 sof Exp $
  *
  * openFile Runtime Support
  */
@@ -29,6 +29,10 @@
 #include <fcntl.h>
 #endif
 
+#ifdef mingw32_TARGET_OS
+#define O_NOCTTY 0
+#endif
+
 IOFileObject*
 openStdFile(fd,flags,rd)
 StgInt fd;
@@ -63,7 +67,7 @@ StgInt flags;
     FILE *fp;
     int fd;
     int oflags;
-    int exclusive;
+    int for_writing;
     int created = 0;
     struct stat sb;
     IOFileObject* fo;
@@ -76,19 +80,19 @@ StgInt flags;
     switch (how) {
       case OPENFILE_APPEND:
         oflags = O_WRONLY | O_NOCTTY | O_APPEND; 
-	exclusive = 1;
+	for_writing = 1;
 	break;
       case OPENFILE_WRITE:
 	oflags = O_WRONLY | O_NOCTTY;
-	exclusive = 1;
+	for_writing = 1;
 	break;
     case OPENFILE_READ_ONLY:
         oflags = O_RDONLY | O_NOCTTY;
-	exclusive = 0;
+	for_writing = 0;
 	break;
     case OPENFILE_READ_WRITE:
 	oflags = O_RDWR | O_NOCTTY;
-	exclusive = 0;
+	for_writing = 1;
 	break;
     default:
 	fprintf(stderr, "openFile: unknown mode `%d'\n", how);
@@ -110,12 +114,14 @@ StgInt flags;
 		return NULL;
 	    } else {
 		/* If it is a dangling symlink, break off now, too. */
+#ifndef mingw32_TARGET_OS
 		struct stat st;
 		if ( lstat(file,&st) == 0) {
 		   ghc_errtype = ERR_NOSUCHTHING;
 		   ghc_errstr = "dangling symlink";
 		   return NULL;
 		}
+#endif
             }
 	    /* Now try to create it */
 	    while ((fd = open(file, oflags | O_CREAT | O_EXCL, 0666)) < 0) {
@@ -186,7 +192,7 @@ StgInt flags;
     }
     /* Use our own personal locking */
 
-    if (lockFile(fd, exclusive) < 0) {
+    if (lockFile(fd, for_writing, 1/*enforce single-writer, if needs be.*/) < 0) {
 	cvtErrno();
 	switch (ghc_errno) {
 	default:
@@ -268,11 +274,13 @@ StgInt fd;
 StgInt oflags;
 StgInt flags;
 {
-    int exclusive;
+    int for_writing;
     FILE* fp;
     IOFileObject* fo;
 
-    if (lockFile(fd, exclusive) < 0) {
+    for_writing = ( ((oflags & O_WRONLY) || (oflags & O_RDWR)) ? 1 : 0);
+
+    if (lockFile(fd, for_writing, 1/* enforce single-writer */ ) < 0) {
 	cvtErrno();
 	switch (ghc_errno) {
 	default:
diff --git a/ghc/lib/std/cbits/stgio.h b/ghc/lib/std/cbits/stgio.h
index 68a097974fee..9631807e1bfe 100644
--- a/ghc/lib/std/cbits/stgio.h
+++ b/ghc/lib/std/cbits/stgio.h
@@ -1,7 +1,7 @@
 /* 
  * (c) The GRASP/AQUA Project, Glasgow University, 1994-1998
  *
- * $Id: stgio.h,v 1.9 1999/01/15 17:54:23 sof Exp $
+ * $Id: stgio.h,v 1.10 1999/02/04 12:13:16 sof Exp $
  *
  * Helper code for GHC's IO subsystem.
  */
@@ -146,7 +146,7 @@ StgAddr getCurrentDirectory(void);
 StgAddr getDirectoryContents (StgByteArray);
 
 /* getLock.c */
-int     lockFile    (int, int);
+int     lockFile    (int, int, int);
 int     unlockFile  (int);
 StgInt	getLock	    (StgInt, StgInt);
 
-- 
GitLab