Implement POSIX file descriptors and I/O
authorcoderain <coderain@sdf.org>
Sat, 28 Oct 2017 21:44:35 +0000 (23:44 +0200)
committercoderain <coderain@sdf.org>
Sat, 28 Oct 2017 21:44:35 +0000 (23:44 +0200)
crt/include/fcntl.h [new file with mode: 0644]
crt/src/fcntl.c [new file with mode: 0644]

diff --git a/crt/include/fcntl.h b/crt/include/fcntl.h
new file mode 100644 (file)
index 0000000..5a83b8c
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * fcntl.h
+ *
+ * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef _FCNTL_H_
+#define _FCNTL_H_
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#endif
diff --git a/crt/src/fcntl.c b/crt/src/fcntl.c
new file mode 100644 (file)
index 0000000..cc7da88
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * fcntl.c
+ *
+ * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <monolithium.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define __DONT_DEFINE_OPEN__
+#include <fcntl.h>
+
+#define MAX_OPEN_FILES 4096
+
+static handle_t mutex;
+static struct
+{
+    handle_t handle;
+    int flags;
+    off_t position;
+    size_t size;
+} descriptors[MAX_OPEN_FILES];
+
+handle_t __crt_get_raw_handle(int fd)
+{
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+    handle_t handle = descriptors[fd].handle;
+    syscall_release_mutex(mutex);
+    return handle;
+}
+
+int open(const char *pathname, int flags, mode_t mode)
+{
+    char fullpath[PATH_MAX];
+
+    if (*pathname == '/')
+    {
+        if (strlen(pathname) >= PATH_MAX)
+        {
+            errno = ENAMETOOLONG;
+            return -1;
+        }
+
+        strcpy(fullpath, pathname);
+    }
+    else
+    {
+        getwd(fullpath);
+
+        if (strlen(fullpath) + strlen(pathname) >= PATH_MAX)
+        {
+            errno = ENAMETOOLONG;
+            return -1;
+        }
+
+        strcat(fullpath, pathname);
+    }
+
+    if ((flags & 3) == 3)
+    {
+        errno = EINVAL;
+        return -1;
+    }
+
+    int fd;
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    for (fd = 0; fd < MAX_OPEN_FILES; fd++)
+    {
+        if (descriptors[fd].handle == INVALID_HANDLE) break;
+    }
+
+    if (fd == MAX_OPEN_FILES)
+    {
+        fd = -1;
+        errno = EMFILE;
+        goto cleanup;
+    }
+
+    dword_t kernel_flags = FILE_MODE_SHARE_READ | FILE_MODE_SHARE_WRITE;
+    dword_t attributes = 0;
+
+    if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_READ;
+    else if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_WRITE;
+    else kernel_flags |= FILE_MODE_READ | FILE_MODE_WRITE;
+
+    if (flags & O_CREAT) kernel_flags |= FILE_MODE_CREATE;
+    if (flags & O_TRUNC) kernel_flags |= FILE_MODE_TRUNCATE;
+
+    sysret_t status = syscall_open_file(fullpath, &descriptors[fd].handle, kernel_flags, attributes);
+    if (status != ERR_SUCCESS)
+    {
+        errno = __crt_translate_error(status);
+        fd = -1;
+        goto cleanup;
+    }
+
+    descriptors[fd].flags = flags;
+
+cleanup:
+    syscall_release_mutex(mutex);
+    return fd;
+}
+
+int creat(const char *pathname, mode_t mode)
+{
+    return open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
+}
+
+int close(int fd)
+{
+    int ret = -1;
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
+    {
+        errno = EBADF;
+        goto cleanup;
+    }
+
+    syscall_close_object(descriptors[fd].handle);
+    descriptors[fd].handle = INVALID_HANDLE;
+    ret = 0;
+
+cleanup:
+    syscall_release_mutex(mutex);
+    return ret;
+}
+
+ssize_t read(int fd, void *buf, size_t count)
+{
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    size_t ret;
+    sysret_t status = syscall_read_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
+
+    descriptors[fd].position += (off_t)ret;
+
+    if (status != ERR_SUCCESS && status != ERR_BEYOND)
+    {
+        errno = __crt_translate_error(status);
+        ret = (off_t)-1;
+    }
+
+    syscall_release_mutex(mutex);
+    return (ssize_t)ret;
+}
+
+ssize_t write(int fd, const void *buf, size_t count)
+{
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    size_t ret;
+    sysret_t status = syscall_write_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
+
+    descriptors[fd].position += (off_t)ret;
+
+    if (status != ERR_SUCCESS && status != ERR_BEYOND)
+    {
+        errno = __crt_translate_error(status);
+        ret = (off_t)-1;
+    }
+
+    syscall_release_mutex(mutex);
+    return (ssize_t)ret;
+}
+
+off_t lseek(int fd, off_t offset, int whence)
+{
+    if (whence < SEEK_SET || whence > SEEK_END)
+    {
+        errno = EINVAL;
+        return (off_t)-1;
+    }
+
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
+    {
+        errno = EBADF;
+        goto cleanup;
+    }
+
+    off_t origin = 0;
+    if (whence == SEEK_CUR) origin = descriptors[fd].position;
+    else if (whence == SEEK_END) origin = descriptors[fd].size;
+
+    off_t ret = origin + offset;
+
+    if ((offset > 0 && ret < origin) || (offset < 0 && ret > origin))
+    {
+        errno = EOVERFLOW;
+        goto cleanup;
+    }
+
+    descriptors[fd].position = ret;
+
+cleanup:
+    syscall_release_mutex(mutex);
+    return ret;
+}
+
+int __crt_initialize_files(process_params_t *params)
+{
+    sysret_t ret = syscall_create_mutex(NULL, TRUE, &mutex);
+    if (ret != ERR_SUCCESS) return -1;
+
+    descriptors[STDIN_FILENO].handle  = params->standard_input;
+    descriptors[STDIN_FILENO].flags   = O_RDONLY;
+    descriptors[STDOUT_FILENO].handle = params->standard_output;
+    descriptors[STDOUT_FILENO].flags  = O_WRONLY;
+    descriptors[STDERR_FILENO].handle = params->standard_error;
+    descriptors[STDERR_FILENO].flags  = O_WRONLY;
+
+    int i;
+    for (i = 3; i < MAX_OPEN_FILES; i++) descriptors[i].handle = INVALID_HANDLE;
+
+    return 0;
+}