cc7da88ff863c295e7839cefbe8dfb22fecb8af8
[monolithium.git] / crt / src / fcntl.c
1 /*
2  * fcntl.c
3  *
4  * Copyright (C) 2017 Aleksandar Andrejevic <theflash@sdf.lonestar.org>
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include <monolithium.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 #define __DONT_DEFINE_OPEN__
25 #include <fcntl.h>
26
27 #define MAX_OPEN_FILES 4096
28
29 static handle_t mutex;
30 static struct
31 {
32     handle_t handle;
33     int flags;
34     off_t position;
35     size_t size;
36 } descriptors[MAX_OPEN_FILES];
37
38 handle_t __crt_get_raw_handle(int fd)
39 {
40     syscall_wait_mutex(mutex, NO_TIMEOUT);
41     handle_t handle = descriptors[fd].handle;
42     syscall_release_mutex(mutex);
43     return handle;
44 }
45
46 int open(const char *pathname, int flags, mode_t mode)
47 {
48     char fullpath[PATH_MAX];
49
50     if (*pathname == '/')
51     {
52         if (strlen(pathname) >= PATH_MAX)
53         {
54             errno = ENAMETOOLONG;
55             return -1;
56         }
57
58         strcpy(fullpath, pathname);
59     }
60     else
61     {
62         getwd(fullpath);
63
64         if (strlen(fullpath) + strlen(pathname) >= PATH_MAX)
65         {
66             errno = ENAMETOOLONG;
67             return -1;
68         }
69
70         strcat(fullpath, pathname);
71     }
72
73     if ((flags & 3) == 3)
74     {
75         errno = EINVAL;
76         return -1;
77     }
78
79     int fd;
80     syscall_wait_mutex(mutex, NO_TIMEOUT);
81
82     for (fd = 0; fd < MAX_OPEN_FILES; fd++)
83     {
84         if (descriptors[fd].handle == INVALID_HANDLE) break;
85     }
86
87     if (fd == MAX_OPEN_FILES)
88     {
89         fd = -1;
90         errno = EMFILE;
91         goto cleanup;
92     }
93
94     dword_t kernel_flags = FILE_MODE_SHARE_READ | FILE_MODE_SHARE_WRITE;
95     dword_t attributes = 0;
96
97     if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_READ;
98     else if ((flags & 3) == O_RDONLY) kernel_flags |= FILE_MODE_WRITE;
99     else kernel_flags |= FILE_MODE_READ | FILE_MODE_WRITE;
100
101     if (flags & O_CREAT) kernel_flags |= FILE_MODE_CREATE;
102     if (flags & O_TRUNC) kernel_flags |= FILE_MODE_TRUNCATE;
103
104     sysret_t status = syscall_open_file(fullpath, &descriptors[fd].handle, kernel_flags, attributes);
105     if (status != ERR_SUCCESS)
106     {
107         errno = __crt_translate_error(status);
108         fd = -1;
109         goto cleanup;
110     }
111
112     descriptors[fd].flags = flags;
113
114 cleanup:
115     syscall_release_mutex(mutex);
116     return fd;
117 }
118
119 int creat(const char *pathname, mode_t mode)
120 {
121     return open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
122 }
123
124 int close(int fd)
125 {
126     int ret = -1;
127     syscall_wait_mutex(mutex, NO_TIMEOUT);
128
129     if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
130     {
131         errno = EBADF;
132         goto cleanup;
133     }
134
135     syscall_close_object(descriptors[fd].handle);
136     descriptors[fd].handle = INVALID_HANDLE;
137     ret = 0;
138
139 cleanup:
140     syscall_release_mutex(mutex);
141     return ret;
142 }
143
144 ssize_t read(int fd, void *buf, size_t count)
145 {
146     syscall_wait_mutex(mutex, NO_TIMEOUT);
147
148     size_t ret;
149     sysret_t status = syscall_read_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
150
151     descriptors[fd].position += (off_t)ret;
152
153     if (status != ERR_SUCCESS && status != ERR_BEYOND)
154     {
155         errno = __crt_translate_error(status);
156         ret = (off_t)-1;
157     }
158
159     syscall_release_mutex(mutex);
160     return (ssize_t)ret;
161 }
162
163 ssize_t write(int fd, const void *buf, size_t count)
164 {
165     syscall_wait_mutex(mutex, NO_TIMEOUT);
166
167     size_t ret;
168     sysret_t status = syscall_write_file(descriptors[fd].handle, buf, descriptors[fd].position, count, &ret);
169
170     descriptors[fd].position += (off_t)ret;
171
172     if (status != ERR_SUCCESS && status != ERR_BEYOND)
173     {
174         errno = __crt_translate_error(status);
175         ret = (off_t)-1;
176     }
177
178     syscall_release_mutex(mutex);
179     return (ssize_t)ret;
180 }
181
182 off_t lseek(int fd, off_t offset, int whence)
183 {
184     if (whence < SEEK_SET || whence > SEEK_END)
185     {
186         errno = EINVAL;
187         return (off_t)-1;
188     }
189
190     syscall_wait_mutex(mutex, NO_TIMEOUT);
191
192     if (fd < 0 || fd >= MAX_OPEN_FILES || descriptors[fd].handle == INVALID_HANDLE)
193     {
194         errno = EBADF;
195         goto cleanup;
196     }
197
198     off_t origin = 0;
199     if (whence == SEEK_CUR) origin = descriptors[fd].position;
200     else if (whence == SEEK_END) origin = descriptors[fd].size;
201
202     off_t ret = origin + offset;
203
204     if ((offset > 0 && ret < origin) || (offset < 0 && ret > origin))
205     {
206         errno = EOVERFLOW;
207         goto cleanup;
208     }
209
210     descriptors[fd].position = ret;
211
212 cleanup:
213     syscall_release_mutex(mutex);
214     return ret;
215 }
216
217 int __crt_initialize_files(process_params_t *params)
218 {
219     sysret_t ret = syscall_create_mutex(NULL, TRUE, &mutex);
220     if (ret != ERR_SUCCESS) return -1;
221
222     descriptors[STDIN_FILENO].handle  = params->standard_input;
223     descriptors[STDIN_FILENO].flags   = O_RDONLY;
224     descriptors[STDOUT_FILENO].handle = params->standard_output;
225     descriptors[STDOUT_FILENO].flags  = O_WRONLY;
226     descriptors[STDERR_FILENO].handle = params->standard_error;
227     descriptors[STDERR_FILENO].flags  = O_WRONLY;
228
229     int i;
230     for (i = 3; i < MAX_OPEN_FILES; i++) descriptors[i].handle = INVALID_HANDLE;
231
232     return 0;
233 }