1 /*
2 * Copyright (c) 2023 Institute of Parallel And Distributed Systems (IPADS), Shanghai Jiao Tong University (SJTU)
3 * Licensed under the Mulan PSL v2.
4 * You can use this software according to the terms and conditions of the Mulan PSL v2.
5 * You may obtain a copy of Mulan PSL v2 at:
6 * http://license.coscl.org.cn/MulanPSL2
7 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
8 * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
9 * PURPOSE.
10 * See the Mulan PSL v2 for more details.
11 */
12
13 #include <atomic.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include "fd.h"
18 #include <chcore/bug.h>
19 #include <limits.h>
20
21 /*
22 * No lock is used to protect fd_dic and its member
23 * since we only modify the fd_desc when init by far ...
24 */
25 /* Global fd desc table */
26 struct fd_desc *fd_dic[MAX_FD] = {0};
27 struct htable fs_cap_struct_htable;
28 /* Default fd operations */
29 struct fd_ops default_ops;
30
31 /*
32 * Helper function.
33 */
iov_check(const struct iovec * iov,int iovcnt)34 static int iov_check(const struct iovec *iov, int iovcnt)
35 {
36 int iov_i;
37 size_t iov_len_sum;
38
39 if (iovcnt <= 0 || iovcnt > IOV_MAX)
40 return -EINVAL;
41
42 iov_len_sum = 0;
43 for (iov_i = 0; iov_i < iovcnt; iov_i++)
44 iov_len_sum += (iov + iov_i)->iov_len;
45
46 return 0;
47 }
48
alloc_fd(void)49 int alloc_fd(void)
50 {
51 return alloc_fd_since(0);
52 }
53
alloc_fd_since(int min)54 int alloc_fd_since(int min)
55 {
56 int cur_fd, ret;
57 struct fd_desc *new_desc;
58 struct fd_record_extension *fd_ext;
59
60 /* Malloc fd_desc structure */
61 new_desc = malloc(sizeof(struct fd_desc));
62 if (new_desc == NULL) {
63 return -ENOMEM;
64 }
65 /* Init fd_desc structure */
66 memset(new_desc, 0, sizeof(struct fd_desc));
67 /* Set default operation */
68 new_desc->fd_op = &default_ops;
69
70 /* XXX: performance */
71 cur_fd = MIN_FD > min ? MIN_FD : min;
72 for (; cur_fd < MAX_FD; cur_fd++) {
73 if (!fd_dic[cur_fd]
74 && a_cas_p((void *)&fd_dic[cur_fd], 0, new_desc) == 0)
75 break;
76 }
77 if (cur_fd == MAX_FD) {
78 ret = -ENFILE;
79 goto out_free_new_desc;
80 }
81
82 /* libfs */
83 fd_ext = _new_fd_record_extension();
84
85 if (fd_ext == NULL) {
86 ret = -ENOMEM;
87 goto out_reset_cur_fd;
88 }
89
90 fd_dic[cur_fd]->private_data = (void *)fd_ext;
91 return cur_fd;
92
93 out_reset_cur_fd:
94 fd_dic[cur_fd] = NULL;
95
96 out_free_new_desc:
97 free(new_desc);
98
99 return ret;
100 }
101
102 /* XXX Concurrent problem */
free_fd(int fd)103 void free_fd(int fd)
104 {
105 free(fd_dic[fd]);
106 fd_dic[fd] = 0;
107 }
108
109 /* fd opeartions */
chcore_read(int fd,void * buf,size_t count)110 ssize_t chcore_read(int fd, void *buf, size_t count)
111 {
112 if (fd < 0 || fd_dic[fd] == 0)
113 return -EBADF;
114 return fd_dic[fd]->fd_op->read(fd, buf, count);
115 }
116
chcore_write(int fd,void * buf,size_t count)117 ssize_t chcore_write(int fd, void *buf, size_t count)
118 {
119 if (fd < 0 || fd_dic[fd] == 0)
120 return -EBADF;
121 return fd_dic[fd]->fd_op->write(fd, buf, count);
122 }
123
chcore_close(int fd)124 int chcore_close(int fd)
125 {
126 if (fd < 0 || fd_dic[fd] == 0)
127 return -EBADF;
128 return fd_dic[fd]->fd_op->close(fd);
129 }
130
chcore_ioctl(int fd,unsigned long request,void * arg)131 int chcore_ioctl(int fd, unsigned long request, void *arg)
132 {
133 if (fd < 0 || fd_dic[fd] == 0)
134 return -EBADF;
135 return fd_dic[fd]->fd_op->ioctl(fd, request, arg);
136 }
137
chcore_fcntl(int fd,int cmd,int arg)138 int chcore_fcntl(int fd, int cmd, int arg)
139 {
140 if (fd < 0 || fd_dic[fd] == 0)
141 return -EBADF;
142 switch (cmd) {
143 case F_DUPFD_CLOEXEC:
144 case F_DUPFD:
145 case F_SETFL:
146 case F_GETFL:
147 return fd_dic[fd]->fd_op->fcntl(fd, cmd, arg);
148 case F_GETFD: // gets fd flag
149 return fd_dic[fd]->flags;
150 case F_SETFD: // sets fd flag
151 // Note: Posix only defines FD_CLOEXEC as file
152 // descriptor flags. However it explicitly allows
153 // implementation stores other status flags.
154 fd_dic[fd]->flags = (arg & FD_CLOEXEC)
155 | (fd_dic[fd]->flags & ~FD_CLOEXEC);
156 return 0;
157 case F_GETOWN:
158 warn("fcntl (F_GETOWN, 0x%x, 0x%x) not implemeted, do "
159 "nothing.\n",
160 cmd,
161 arg);
162 break;
163 case F_SETOWN:
164 warn("fcntl (F_SETOWN, 0x%x, 0x%x) not implemeted, do "
165 "nothing.\n",
166 cmd,
167 arg);
168 break;
169 case F_GETLK:
170 warn("fcntl (F_GETLK, 0x%x, 0x%x) not implemeted, do "
171 "nothing.\n",
172 cmd,
173 arg);
174 break;
175 case F_SETLK:
176 warn("fcntl (F_SETLK, 0x%x, 0x%x) not implemeted, do "
177 "nothing.\n",
178 cmd,
179 arg);
180 break;
181 case F_SETLKW:
182 warn("fcntl (F_SETLKW, 0x%x, 0x%x) not implemeted, do "
183 "nothing.\n",
184 cmd,
185 arg);
186 break;
187 default:
188 return -EINVAL;
189 }
190 return -1;
191 }
192
chcore_readv(int fd,const struct iovec * iov,int iovcnt)193 ssize_t chcore_readv(int fd, const struct iovec *iov, int iovcnt)
194 {
195 int iov_i;
196 ssize_t byte_read, ret;
197
198 if ((ret = iov_check(iov, iovcnt)) != 0)
199 return ret;
200
201 byte_read = 0;
202 for (iov_i = 0; iov_i < iovcnt; iov_i++) {
203 ret = chcore_read(fd,
204 (void *)((iov + iov_i)->iov_base),
205 (size_t)(iov + iov_i)->iov_len);
206 if (ret < 0) {
207 return ret;
208 }
209
210 byte_read += ret;
211 if (ret != (iov + iov_i)->iov_len) {
212 return byte_read;
213 }
214 }
215
216 return byte_read;
217 }
218
chcore_writev(int fd,const struct iovec * iov,int iovcnt)219 ssize_t chcore_writev(int fd, const struct iovec *iov, int iovcnt)
220 {
221 int iov_i;
222 ssize_t byte_written, ret;
223
224 if ((ret = iov_check(iov, iovcnt)) != 0)
225 return ret;
226
227 byte_written = 0;
228 for (iov_i = 0; iov_i < iovcnt; iov_i++) {
229 ret = chcore_write(fd,
230 (void *)((iov + iov_i)->iov_base),
231 (size_t)(iov + iov_i)->iov_len);
232 if (ret < 0) {
233 return ret;
234 }
235
236 byte_written += ret;
237 if (ret != (iov + iov_i)->iov_len) {
238 return byte_written;
239 }
240 }
241 return byte_written;
242 }
243
dup_fd_content(int fd,int arg)244 int dup_fd_content(int fd, int arg)
245 {
246 int type, new_fd;
247 if (arg == -1) {
248 new_fd = alloc_fd();
249 } else {
250 new_fd = alloc_fd_since(arg);
251 }
252
253 // alloc_fd_since() is impossible to return new_fd >= MAX_FD in fact.
254 if (new_fd < 0 || new_fd >= MAX_FD) {
255 return new_fd;
256 }
257
258 type = fd_dic[fd]->type;
259 fd_dic[new_fd]->fd = fd_dic[fd]->fd;
260 fd_dic[new_fd]->type = fd_dic[fd]->type;
261 fd_dic[new_fd]->fd_op = fd_dic[fd]->fd_op;
262 if (type == FD_TYPE_SOCK || type == FD_TYPE_FILE) {
263 fd_dic[new_fd]->cap = fd_dic[fd]->cap;
264 fd_dic[new_fd]->flags = fd_dic[fd]->flags;
265 } else if (type == FD_TYPE_STDIN || type == FD_TYPE_STDOUT
266 || type == FD_TYPE_STDIN)
267 fd_dic[new_fd]->termios = fd_dic[fd]->termios;
268 return new_fd;
269 }
270
271 /* Default file operation */
272
273 /* TYPE TO STRING */
274 static char fd_type[][20] = {
275 "FILE",
276 "PIPE",
277 "SCOK",
278 "STDIN",
279 "STDOUT",
280 "STDERR",
281 "EVENT",
282 "TIMER",
283 "EPOLL",
284 };
285
fd_default_read(int fd,void * buf,size_t size)286 static ssize_t fd_default_read(int fd, void *buf, size_t size)
287 {
288 printf("READ fd %d type %s not impl!\n", fd, fd_type[fd_dic[fd]->type]);
289 return -EINVAL;
290 }
291
fd_default_write(int fd,void * buf,size_t size)292 static ssize_t fd_default_write(int fd, void *buf, size_t size)
293 {
294 printf("WRITE fd %d type %s not impl!\n", fd, fd_type[fd_dic[fd]->type]);
295 return -EINVAL;
296 }
297
fd_default_close(int fd)298 static int fd_default_close(int fd)
299 {
300 printf("CLOSE fd %d type %s not impl!\n", fd, fd_type[fd_dic[fd]->type]);
301 return -EINVAL;
302 }
303
fd_default_poll(int fd,struct pollarg * arg)304 static int fd_default_poll(int fd, struct pollarg *arg)
305 {
306 printf("POLL fd %d type %s not impl!\n", fd, fd_type[fd_dic[fd]->type]);
307 return -EINVAL;
308 }
309
fd_default_ioctl(int fd,unsigned long request,void * arg)310 static int fd_default_ioctl(int fd, unsigned long request, void *arg)
311 {
312 printf("IOCTL fd %d type %s not impl!\n", fd, fd_type[fd_dic[fd]->type]);
313 return -EINVAL;
314 }
315
316 struct fd_ops default_ops = {
317 .read = fd_default_read,
318 .write = fd_default_write,
319 .close = fd_default_close,
320 .poll = fd_default_poll,
321 .ioctl = fd_default_ioctl,
322 };
323