[crt] Improve file descriptors
authorcoderain <coderain@sdf.org>
Wed, 15 Nov 2017 04:14:26 +0000 (05:14 +0100)
committercoderain <coderain@sdf.org>
Wed, 15 Nov 2017 04:14:26 +0000 (05:14 +0100)
crt/include/fcntl.h
crt/src/fcntl.c

index 5a83b8cb92706434eeedbf7a5a94e042fd82661d..5f373a531ce78b06b70d35d8c47c0132f12346a4 100644 (file)
@@ -23,4 +23,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 
+#define FD_CLOEXEC (1 << 0)
+#define FD_PIPE    (1 << 1)
+
 #endif
index cc7da88ff863c295e7839cefbe8dfb22fecb8af8..a8b710914323aee64e518ab6cf661143c40b5e39 100644 (file)
@@ -31,6 +31,7 @@ static struct
 {
     handle_t handle;
     int flags;
+    int descriptor_flags;
     off_t position;
     size_t size;
 } descriptors[MAX_OPEN_FILES];
@@ -43,8 +44,73 @@ handle_t __crt_get_raw_handle(int fd)
     return handle;
 }
 
+static inline int __crt_open_handle_at(int fd, handle_t handle, int flags)
+{
+    object_type_t type;
+    sysret_t status = syscall_query_handle(handle, HANDLE_INFO_TYPE, &type, sizeof(type));
+
+    if (status != ERR_SUCCESS || (type != OBJECT_FILE && type != OBJECT_PIPE))
+    {
+        errno = EINVAL;
+        return -1;
+    }
+
+    if (type == OBJECT_FILE)
+    {
+        qword_t real_size;
+        status = syscall_query_file(handle, FILE_INFO_SIZE, &real_size, sizeof(real_size));
+        if (status != ERR_SUCCESS)
+        {
+            errno = __crt_translate_error(status);
+            return -1;
+        }
+
+        if (real_size > (qword_t)((size_t)-1))
+        {
+            errno = EFBIG;
+            return -1;
+        }
+
+        descriptors[fd].descriptor_flags = 0;
+        descriptors[fd].size = (size_t)real_size;
+    }
+    else
+    {
+        descriptors[fd].descriptor_flags = FD_PIPE;
+        descriptors[fd].size = 0;
+    }
+
+    descriptors[fd].handle = handle;
+    descriptors[fd].flags = flags;
+    descriptors[fd].position = 0;
+    return fd;
+}
+
+static inline int __crt_open_handle(handle_t handle, int flags)
+{
+    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)
+    {
+        errno = EMFILE;
+        return -1;
+    }
+
+    fd = __crt_open_handle_at(fd, handle, flags);
+
+    syscall_release_mutex(mutex);
+    return fd;
+}
+
 int open(const char *pathname, int flags, mode_t mode)
 {
+    handle_t handle;
     char fullpath[PATH_MAX];
 
     if (*pathname == '/')
@@ -76,21 +142,6 @@ int open(const char *pathname, int flags, mode_t mode)
         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;
 
@@ -101,18 +152,15 @@ int open(const char *pathname, int flags, mode_t mode)
     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);
+    sysret_t status = syscall_open_file(fullpath, &handle, kernel_flags, attributes);
     if (status != ERR_SUCCESS)
     {
         errno = __crt_translate_error(status);
-        fd = -1;
-        goto cleanup;
+        return -1;
     }
 
-    descriptors[fd].flags = flags;
-
-cleanup:
-    syscall_release_mutex(mutex);
+    int fd = __crt_open_handle(handle, flags);
+    if (fd < 0) syscall_close_object(handle);
     return fd;
 }
 
@@ -195,6 +243,12 @@ off_t lseek(int fd, off_t offset, int whence)
         goto cleanup;
     }
 
+    if (descriptors[fd].descriptor_flags & FD_PIPE)
+    {
+        errno = ESPIPE;
+        goto cleanup;
+    }
+
     off_t origin = 0;
     if (whence == SEEK_CUR) origin = descriptors[fd].position;
     else if (whence == SEEK_END) origin = descriptors[fd].size;
@@ -214,20 +268,55 @@ cleanup:
     return ret;
 }
 
+int dup(int oldfd)
+{
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    handle_t duplicate;
+    int flags = descriptors[oldfd].flags;
+    sysret_t status = syscall_duplicate_handle(INVALID_HANDLE, descriptors[oldfd].handle, INVALID_HANDLE, &duplicate);
+    syscall_release_mutex(mutex);
+
+    if (status != ERR_SUCCESS)
+    {
+        errno = __crt_translate_error(status);
+        return -1;
+    }
+
+    return __crt_open_handle(duplicate, flags);
+}
+
+int dup2(int oldfd, int newfd)
+{
+    int fd = -1;
+    syscall_wait_mutex(mutex, NO_TIMEOUT);
+
+    handle_t duplicate;
+    sysret_t status = syscall_duplicate_handle(INVALID_HANDLE, descriptors[oldfd].handle, INVALID_HANDLE, &duplicate);
+
+    if (status != ERR_SUCCESS)
+    {
+        errno = __crt_translate_error(status);
+        goto cleanup;
+    }
+
+    fd = __crt_open_handle_at(newfd, duplicate, descriptors[oldfd].flags);
+
+cleanup:
+    syscall_release_mutex(mutex);
+    return fd;
+}
+
 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;
+    for (i = 0; i < MAX_OPEN_FILES; i++) descriptors[i].handle = INVALID_HANDLE;
 
+    if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDIN_FILENO, params->standard_input, O_RDONLY);
+    if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDOUT_FILENO, params->standard_output, O_WRONLY);
+    if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDERR_FILENO, params->standard_error, O_WRONLY);
     return 0;
 }