shithub: scc

Download patch

ref: 2a61dfcd596b6da4d31379663a20e4fe0566cc17
parent: f764b7c8342bd000d43eea624bc6265b8f3a8a7f
author: Michael Forney <mforney@mforney.org>
date: Sat Oct 2 21:27:57 EDT 2021

libc: Fix fopen with mode "r"

On all supported platforms, O_RDONLY is 0, so flags & O_RDONLY is
never true and the FILE does not get marked as _IOREAD, causing all
read operations to fail with EBADF.

To fix this, introduce O_ACCMODE in sys.h, containing a mask of the
bits used for the file access mode. Then, in _fpopen, switch on
access mode.

--- a/include/bits/darwin/sys.h
+++ b/include/bits/darwin/sys.h
@@ -1,6 +1,7 @@
 #define O_RDONLY  0x00000000
 #define O_WRONLY  0x00000001
 #define O_RDWR    0x00000002
+#define O_ACCMODE 0x00000003
 
 #define O_TRUNC   0x00000400
 #define O_APPEND  0x00000008
--- a/include/bits/dragonfly/sys.h
+++ b/include/bits/dragonfly/sys.h
@@ -1,6 +1,7 @@
 #define O_RDONLY  0x00000000
 #define O_WRONLY  0x00000001
 #define O_RDWR    0x00000002
+#define O_ACCMODE 0x00000003
 
 #define O_TRUNC   0x00000400
 #define O_APPEND  0x00000008
--- a/include/bits/linux/sys.h
+++ b/include/bits/linux/sys.h
@@ -1,6 +1,7 @@
 #define O_RDONLY  0x00000000
 #define O_WRONLY  0x00000001
 #define O_RDWR    0x00000002
+#define O_ACCMODE 0x00000003
 
 #define O_TRUNC   0x00000200
 #define O_APPEND  0x00000400
--- a/include/bits/netbsd/sys.h
+++ b/include/bits/netbsd/sys.h
@@ -1,6 +1,7 @@
 #define O_RDONLY  0x00000000
 #define O_WRONLY  0x00000001
 #define O_RDWR    0x00000002
+#define O_ACCMODE 0x00000003
 
 #define O_TRUNC   0x00000400
 #define O_APPEND  0x00000008
--- a/include/bits/openbsd/sys.h
+++ b/include/bits/openbsd/sys.h
@@ -1,6 +1,7 @@
 #define O_RDONLY  0x00000000
 #define O_WRONLY  0x00000001
 #define O_RDWR    0x00000002
+#define O_ACCMODE 0x00000003
 
 #define O_TRUNC   0x00000400
 #define O_APPEND  0x00000008
--- a/src/libc/stdio/_fpopen.c
+++ b/src/libc/stdio/_fpopen.c
@@ -63,12 +63,17 @@
 	if (!bin)
 		fp->flags |= _IOTXT;
 
-	if (flags & O_RDWR)
+	switch (flags & O_ACCMODE) {
+	case O_RDWR:
 		fp->flags |= _IORW;
-	else if (flags & O_RDONLY)
+		break;
+	case O_RDONLY:
 		fp->flags |= _IOREAD;
-	else
+		break;
+	case O_WRONLY:
 		fp->flags |= _IOWRITE;
+		break;
+	}
 
 	fp->lp = fp->rp = fp->wp = NULL;