• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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