[PATCH v2 13/15] tools/nolibc: add fopen()

Thomas Weißschuh posted 15 patches 7 months, 3 weeks ago
[PATCH v2 13/15] tools/nolibc: add fopen()
Posted by Thomas Weißschuh 7 months, 3 weeks ago
This is used in various selftests and will be handy when integrating
those with nolibc.

Only the standard POSIX modes are supported.
No extensions nor the (noop) "b" from ISO C are accepted.

Signed-off-by: Thomas Weißschuh <thomas.weissschuh@linutronix.de>
Acked-by: Willy Tarreau <w@1wt.eu>
---
 tools/include/nolibc/stdio.h                 | 20 ++++++++++++++++++++
 tools/testing/selftests/nolibc/nolibc-test.c | 24 ++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
index df5717d591826c8468e3473581ac0d6e76629aa3..61b7252ab6d04f8758367f5265687146326456a3 100644
--- a/tools/include/nolibc/stdio.h
+++ b/tools/include/nolibc/stdio.h
@@ -13,6 +13,7 @@
 #include "std.h"
 #include "arch.h"
 #include "errno.h"
+#include "fcntl.h"
 #include "types.h"
 #include "sys.h"
 #include "stdarg.h"
@@ -55,6 +56,25 @@ FILE *fdopen(int fd, const char *mode __attribute__((unused)))
 	return (FILE*)(intptr_t)~fd;
 }
 
+static __attribute__((unused))
+FILE *fopen(const char *pathname, const char *mode)
+{
+	int flags, fd;
+
+        switch (*mode) {
+                case 'r': flags = O_RDONLY; break;
+                case 'w': flags = O_WRONLY | O_CREAT | O_TRUNC; break;
+                case 'a': flags = O_WRONLY | O_CREAT | O_APPEND; break;
+                default : SET_ERRNO(EINVAL); return NULL;
+        }
+
+        if (mode[1] == '+')
+                flags = (flags & ~(O_RDONLY|O_WRONLY)) | O_RDWR;
+
+	fd = open(pathname, flags, 0666);
+	return fdopen(fd, mode);
+}
+
 /* provides the fd of stream. */
 static __attribute__((unused))
 int fileno(FILE *stream)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index d1157319b5d715dbc94ff9203b1d2a2e932aabcf..0391c7d01380ea2f20d1d07497ea1964bcb6a9f4 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -859,6 +859,29 @@ int test_getpagesize(void)
 	return !c;
 }
 
+int test_file_stream(void)
+{
+	FILE *f;
+	int r;
+
+	f = fopen("/dev/null", "r");
+	if (!f)
+		return -1;
+
+	errno = 0;
+	r = fwrite("foo", 1, 3, f);
+	if (r != 0 || errno != EBADF) {
+		fclose(f);
+		return -1;
+	}
+
+	r = fclose(f);
+	if (r == EOF)
+		return -1;
+
+	return 0;
+}
+
 int test_fork(void)
 {
 	int status;
@@ -1311,6 +1334,7 @@ int run_syscall(int min, int max)
 		CASE_TEST(dup3_0);            tmp = dup3(0, 100, 0);  EXPECT_SYSNE(1, tmp, -1); close(tmp); break;
 		CASE_TEST(dup3_m1);           tmp = dup3(-1, 100, 0); EXPECT_SYSER(1, tmp, -1, EBADF); if (tmp != -1) close(tmp); break;
 		CASE_TEST(execve_root);       EXPECT_SYSER(1, execve("/", (char*[]){ [0] = "/", [1] = NULL }, NULL), -1, EACCES); break;
+		CASE_TEST(file_stream);       EXPECT_SYSZR(1, test_file_stream()); break;
 		CASE_TEST(fork);              EXPECT_SYSZR(1, test_fork()); break;
 		CASE_TEST(getdents64_root);   EXPECT_SYSNE(1, test_getdents64("/"), -1); break;
 		CASE_TEST(getdents64_null);   EXPECT_SYSER(1, test_getdents64("/dev/null"), -1, ENOTDIR); break;

-- 
2.49.0