4 * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <monolithium.h>
24 #define __DONT_DEFINE_OPEN__
27 #define MAX_OPEN_FILES 4096
29 static handle_t mutex;
37 } descriptors[MAX_OPEN_FILES];
39 handle_t __crt_get_raw_handle(int fd)
41 syscall_wait_mutex(mutex, NO_TIMEOUT);
42 handle_t handle = descriptors[fd].handle;
43 syscall_release_mutex(mutex);
47 static inline int __crt_open_handle_at(int fd, handle_t handle, int flags)
50 sysret_t status = syscall_query_handle(handle, HANDLE_INFO_TYPE, &type, sizeof(type));
52 if (status != ERR_SUCCESS || (type != OBJECT_FILE && type != OBJECT_PIPE))
58 if (type == OBJECT_FILE)
61 status = syscall_query_file(handle, FILE_INFO_SIZE, &real_size, sizeof(real_size));
62 if (status != ERR_SUCCESS)
64 errno = __crt_translate_error(status);
68 if (real_size > (qword_t)((size_t)-1))
74 descriptors[fd].descriptor_flags = 0;
75 descriptors[fd].size = (size_t)real_size;
79 descriptors[fd].descriptor_flags = FD_PIPE;
80 descriptors[fd].size = 0;
83 descriptors[fd].handle = handle;
84 descriptors[fd].flags = flags;
85 descriptors[fd].position = 0;
89 static inline int __crt_open_handle(handle_t handle, int flags)
92 syscall_wait_mutex(mutex, NO_TIMEOUT);
94 for (fd = 0; fd < MAX_OPEN_FILES; fd++)
96 if (descriptors[fd].handle == INVALID_HANDLE) break;
99 if (fd == MAX_OPEN_FILES)
105 fd = __crt_open_handle_at(fd, handle, flags);
107 syscall_release_mutex(mutex);
111 int open(const char *pathname, int flags, mode_t mode)
114 char fullpath[PATH_MAX];
116 if (*pathname == '/')
118 if (strlen(pathname) >= PATH_MAX)
120 errno = ENAMETOOLONG;
124 strcpy(fullpath, pathname);
130 if (strlen(fullpath) + strlen(pathname) >= PATH_MAX)
132 errno = ENAMETOOLONG;
136 strcat(fullpath, pathname);
139 if ((flags & 3) == 3)
145 dword_t kernel_flags = FILE_MODE_SHARE_READ | FILE_MODE_SHARE_WRITE;
146 dword_t attributes = 0;
148 if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_READ;
149 else if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_WRITE;
150 else kernel_flags |= FILE_MODE_READ | FILE_MODE_WRITE;
152 if (flags & O_CREAT) kernel_flags |= FILE_MODE_CREATE;
153 if (flags & O_TRUNC) kernel_flags |= FILE_MODE_TRUNCATE;
155 sysret_t status = syscall_open_file(fullpath, &handle, kernel_flags, attributes);
156 if (status != ERR_SUCCESS)
158 errno = __crt_translate_error(status);
162 int fd = __crt_open_handle(handle, flags);
163 if (fd < 0) syscall_close_object(handle);
167 int creat(const char *pathname, mode_t mode)
169 return open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
175 syscall_wait_mutex(mutex, NO_TIMEOUT);
177 if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
183 syscall_close_object(descriptors[fd].handle);
184 descriptors[fd].handle = INVALID_HANDLE;
188 syscall_release_mutex(mutex);
192 ssize_t read(int fd, void *buf, size_t count)
194 syscall_wait_mutex(mutex, NO_TIMEOUT);
197 sysret_t status = syscall_read_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
199 descriptors[fd].position += (off_t)ret;
201 if (status != ERR_SUCCESS && status != ERR_BEYOND)
203 errno = __crt_translate_error(status);
207 syscall_release_mutex(mutex);
211 ssize_t write(int fd, const void *buf, size_t count)
213 syscall_wait_mutex(mutex, NO_TIMEOUT);
216 sysret_t status = syscall_write_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
218 descriptors[fd].position += (off_t)ret;
220 if (status != ERR_SUCCESS && status != ERR_BEYOND)
222 errno = __crt_translate_error(status);
226 syscall_release_mutex(mutex);
230 off_t lseek(int fd, off_t offset, int whence)
232 if (whence < SEEK_SET || whence > SEEK_END)
238 syscall_wait_mutex(mutex, NO_TIMEOUT);
240 if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
246 if (descriptors[fd].descriptor_flags & FD_PIPE)
253 if (whence == SEEK_CUR) origin = descriptors[fd].position;
254 else if (whence == SEEK_END) origin = descriptors[fd].size;
256 off_t ret = origin + offset;
258 if ((offset > 0 && ret < origin) || (offset < 0 && ret > origin))
264 descriptors[fd].position = ret;
267 syscall_release_mutex(mutex);
273 syscall_wait_mutex(mutex, NO_TIMEOUT);
276 int flags = descriptors[oldfd].flags;
277 sysret_t status = syscall_duplicate_handle(INVALID_HANDLE, descriptors[oldfd].handle, INVALID_HANDLE, &duplicate);
278 syscall_release_mutex(mutex);
280 if (status != ERR_SUCCESS)
282 errno = __crt_translate_error(status);
286 return __crt_open_handle(duplicate, flags);
289 int dup2(int oldfd, int newfd)
292 syscall_wait_mutex(mutex, NO_TIMEOUT);
295 sysret_t status = syscall_duplicate_handle(INVALID_HANDLE, descriptors[oldfd].handle, INVALID_HANDLE, &duplicate);
297 if (status != ERR_SUCCESS)
299 errno = __crt_translate_error(status);
303 fd = __crt_open_handle_at(newfd, duplicate, descriptors[oldfd].flags);
306 syscall_release_mutex(mutex);
310 int __crt_initialize_files(process_params_t *params)
312 sysret_t ret = syscall_create_mutex(NULL, TRUE, &mutex);
313 if (ret != ERR_SUCCESS) return -1;
316 for (i = 0; i < MAX_OPEN_FILES; i++) descriptors[i].handle = INVALID_HANDLE;
318 if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDIN_FILENO, params->standard_input, O_RDONLY);
319 if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDOUT_FILENO, params->standard_output, O_WRONLY);
320 if (params->standard_input != INVALID_HANDLE) __crt_open_handle_at(STDERR_FILENO, params->standard_error, O_WRONLY);