Implement vectored I/O.
[monolithium.git] / crt / src / io.c
index f4338b9ad68507f9df49c7d5e66baf3b90e65c1e..2b461679844b9cc1e7e7bb44f433fe36c5e42c98 100644 (file)
 
 #include <stdio.h>
 #include <unistd.h>
-#include <monolithium.h>
-
-#define FILE_READ        (1 << 0)
-#define FILE_WRITE       (1 << 1)
-#define FILE_APPEND      (1 << 2)
-#define FILE_BUFFER_LINE (1 << 3)
-#define FILE_BUFFER_DIR  (1 << 4)
-#define FILE_BUFFER_FULL (1 << 31)
-
-struct __crt_file
-{
-    list_entry_t link;
-    handle_t mutex;
-    uint32_t flags;
-
-    int fd;
-    size_t size;
-
-    char *buffer;
-    size_t buffer_size;
-    size_t buffer_start, buffer_end;
-};
+#include "io_priv.h"
 
 static list_entry_t open_files;
 
@@ -388,9 +367,61 @@ int puts(const char *s)
     return 0;
 }
 
+FILE *fdopen(int fd, const char *mode)
+{
+    FILE *stream = (FILE*)malloc(sizeof(FILE) + BUFSIZ);
+
+    if (stream == NULL)
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
+
+    sysret_t status = syscall_create_mutex(NULL, TRUE, &stream->mutex);
+    if (status != ERR_SUCCESS)
+    {
+        free(stream);
+        errno = __crt_translate_error(status);
+        return NULL;
+    }
+
+    stream->flags = 0;
+
+    const char *ptr;
+    for (ptr = mode; *ptr; ptr++)
+    {
+        switch (*ptr)
+        {
+        case 'r':
+            stream->flags |= FILE_READ;
+            break;
+        case 'w':
+            stream->flags |= FILE_WRITE;
+            break;
+        case 'a':
+            stream->flags |= FILE_APPEND;
+            break;
+        case '+':
+            stream->flags |= FILE_READ | FILE_WRITE;
+            break;
+        }
+    }
+
+    stream->fd = fd;
+
+    char *buffer = (char*)((uintptr_t)stream + sizeof(FILE));
+    setbuf(stream, buffer);
+    return stream;
+}
+
 FILE *fmemopen(void *buf, size_t size, const char *mode)
 {
     FILE *stream = (FILE*)malloc(sizeof(FILE));
+    if (stream == NULL)
+    {
+        errno = ENOMEM;
+        return NULL;
+    }
 
     sysret_t status = syscall_create_mutex(NULL, TRUE, &stream->mutex);
     if (status != ERR_SUCCESS)
@@ -423,7 +454,6 @@ FILE *fmemopen(void *buf, size_t size, const char *mode)
     }
 
     stream->fd = -1;
-    stream->size = size;
     stream->buffer = buf;
     stream->buffer_size = size;
     stream->buffer_start = stream->buffer_end = 0;
@@ -432,9 +462,47 @@ FILE *fmemopen(void *buf, size_t size, const char *mode)
     return stream;
 }
 
+FILE *fopen(const char *pathname, const char *mode)
+{
+    int open_flags = 0;
+
+    const char *ptr;
+    for (ptr = mode; *ptr; ptr++)
+    {
+        switch (*ptr)
+        {
+        case 'r':
+            open_flags = (open_flags & ~3) | O_RDONLY;
+            break;
+        case 'w':
+            open_flags = (open_flags & ~3) | O_WRONLY;
+            break;
+        case 'a':
+            open_flags |= O_APPEND;
+            break;
+        case '+':
+            open_flags = (open_flags & ~3) | O_RDWR;
+            break;
+        }
+    }
+
+    int fd = open(pathname, open_flags);
+    if (fd < 0) return NULL;
+
+    FILE *stream = fdopen(fd, mode);
+    if (!stream) close(fd);
+    return NULL;
+}
+
 int fclose(FILE *stream)
 {
+    fflush(stream);
     list_remove(&stream->link);
+    syscall_wait_mutex(stream->mutex, NO_TIMEOUT);
+
+    if (stream->fd) close(stream->fd);
+
+    syscall_close_object(stream->mutex);
     free(stream);
     return 0;
 }