• 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 "limits.h"
14 #include <syscall_arch.h>
15 #include <string.h>
16 #include <fcntl.h>
17 #include <sys/ioctl.h>
18 
19 #include <chcore-internal/fs_defs.h>
20 #include <chcore/ipc.h>
21 #include <chcore-internal/procmgr_defs.h>
22 #include <pthread.h>
23 
24 #include "fd.h"
25 #include "fs_client_defs.h"
26 
27 #define debug(fmt, ...) printf("[DEBUG] " fmt, ##__VA_ARGS__)
28 #define warn_once(fmt, ...)       \
29     do {                          \
30         static int __warned = 0;  \
31         if (__warned)             \
32             break;                \
33         __warned = 1;             \
34         warn(fmt, ##__VA_ARGS__); \
35     } while (0)
36 
37 /* helper functions */
fd_not_exists(int fd)38 static inline bool fd_not_exists(int fd)
39 {
40     if (fd < MIN_FD || fd >= MAX_FD || fd_dic[fd] == NULL)
41         return true;
42     return false;
43 }
44 
fd_not_reserve(int fd)45 static inline bool fd_not_reserve(int fd)
46 {
47     return fd != AT_FDCWD && fd != AT_FDROOT;
48 }
49 
check_path_len(const char * path,int buffer_len)50 static inline int check_path_len(const char *path, int buffer_len)
51 {
52     /* NOTE: max_len of full_path is FS_REQ_PATH_LEN */
53     if (strlen(path) > buffer_len) {
54         printf("Too long path with path_len=%d\n", strlen(path));
55         return -1;
56     }
57     return 0;
58 }
59 
access_ok(const char * s)60 static inline bool access_ok(const char *s)
61 {
62 
63     return (s == NULL) ? false : true;
64 }
65 
66 /*
67  * If `path` begins with '/', ignore dirfd,
68  * else concat dirfd corresponding path with `path`
69  *
70  * Return NULL if error occurs,
71  * 	else ALLOCATE buffer for `full_path` and return.
72  *
73  * NOTE: Don't forget to free return buffer.
74  */
generate_full_path(int dirfd,const char * path,char ** full_path_out)75 static int generate_full_path(int dirfd, const char *path, char **full_path_out)
76 {
77     char *full_path;
78 
79     /* Generate full_path */
80     if (!path) {
81         /* path is NULL */
82         if (fd_not_exists(dirfd) && fd_not_reserve(dirfd)) {
83             *full_path_out = NULL;
84             return -EINVAL;
85         }
86         full_path = strdup(path_from_fd(dirfd));
87     } else if (path[0] == '/') {
88         /* Absolute Path */
89         full_path = strdup(path);
90     } else {
91         /* Relative Path */
92         if (fd_not_exists(dirfd) && fd_not_reserve(dirfd)) {
93             *full_path_out = NULL;
94             return -EINVAL;
95         }
96         full_path = path_join(path_from_fd(dirfd), path);
97     }
98 
99     /* Validate full_path */
100     if (full_path == NULL) {
101         return -ENOMEM;
102     }
103     if (check_path_len(full_path, FS_REQ_PATH_LEN) != 0) {
104         free(full_path);
105         *full_path_out = NULL;
106         return -ENAMETOOLONG;
107     }
108 
109     *full_path_out = full_path;
110     return 0;
111 }
112 
113 /*
114  * [IN] full_path: global full path for parsing
115  * [OUT] mount_id: Return from FSM. `mount_id` is an identifier for mount_info
116  * [OUT] server_path: is the path sending to fs_server,
117  * 		removing the prefix of mount_point from `full_path`
118  * return: 0 for success, -1 for some error
119  */
parse_full_path(char * full_path,int * mount_id,char * server_path)120 static inline int parse_full_path(char *full_path, int *mount_id,
121                                   char *server_path)
122 {
123     ipc_msg_t *ipc_msg;
124     struct fsm_request *fsm_req;
125     int ret = 0;
126 
127     ipc_msg = ipc_create_msg(fsm_ipc_struct, sizeof(*fsm_req));
128     if (ipc_msg == NULL) {
129         return -1;
130     }
131     fsm_req = fsm_parse_path_forward(ipc_msg, full_path);
132     if (fsm_req == NULL) {
133         ret = -1;
134         goto out;
135     }
136     *mount_id = fsm_req->mount_id;
137     if (pathcpy(server_path,
138                 FS_REQ_PATH_BUF_LEN,
139                 full_path + fsm_req->mount_path_len,
140                 strlen(full_path + fsm_req->mount_path_len))
141         != 0) {
142         ret = -1;
143         goto out;
144     }
145 
146 out:
147     ipc_destroy_msg(ipc_msg);
148     return ret;
149 }
150 
151 /* file operations */
152 
chcore_chdir(const char * path)153 int chcore_chdir(const char *path)
154 {
155 
156     if (path[0] != '/') {
157         /* Relative Path */
158         path = path_join(cwd_path, path);
159     }
160     if (pathcpy(cwd_path, MAX_CWD_BUF_LEN, path, strlen(path)) != 0)
161         return -EBADF;
162     cwd_len = strlen(path);
163 
164     return 0;
165 }
166 
chcore_fchdir(int fd)167 int chcore_fchdir(int fd)
168 {
169     ipc_msg_t *ipc_msg = 0;
170     struct fs_request *fr_ptr;
171     struct fd_record_extension *fd_ext;
172     int new_cwd_len, ret = 0;
173 
174     if (fd_not_exists(fd))
175         return -EBADF;
176 
177     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
178 
179     if (!fd_ext->path)
180         return -EBADF;
181 
182     new_cwd_len = strlen(fd_ext->path);
183     /* if pathcpy failed, the cwd_path will remain the same */
184     if (pathcpy(cwd_path, MAX_CWD_BUF_LEN, fd_ext->path, new_cwd_len) != 0)
185         return -EBADF;
186 
187     /* pathcpy succeed, change cwd_len */
188     cwd_len = new_cwd_len;
189 
190     return 0;
191 }
192 
chcore_getcwd(char * buf,size_t size)193 char *chcore_getcwd(char *buf, size_t size)
194 {
195     if (pathcpy(buf, size, cwd_path, cwd_len) != 0)
196         return NULL;
197     return buf;
198 }
199 
chcore_ftruncate(int fd,off_t length)200 int chcore_ftruncate(int fd, off_t length)
201 {
202     ipc_msg_t *ipc_msg = 0;
203     ipc_struct_t *_fs_ipc_struct;
204     struct fd_record_extension *fd_ext;
205     struct fs_request *fr_ptr;
206     int ret = 0;
207 
208     if (fd_not_exists(fd))
209         return -EBADF;
210 
211     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
212 
213     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
214     ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
215     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
216 
217     fr_ptr->req = FS_REQ_FTRUNCATE;
218     fr_ptr->ftruncate.fd = fd;
219     fr_ptr->ftruncate.length = length;
220 
221     ret = ipc_call(_fs_ipc_struct, ipc_msg);
222     ipc_destroy_msg(ipc_msg);
223 
224     return ret;
225 }
226 
227 /**
228  * In ChCore, we hijack the syscall function so that many
229  * syscalls are forwarded to userspace wrappers like chcore_lseek
230  * which implicitly exploits IPC to implement the semantics
231  * of hijacked syscall.
232  *
233  * Note that this is a pure userspace process, which doesn't
234  * cross ABI boundary or has nothing to do with ABI, so it's
235  * safe for chcore_lseek to return a 64bit off_t on any architectures.
236  */
chcore_lseek(int fd,off_t offset,int whence)237 off_t chcore_lseek(int fd, off_t offset, int whence)
238 {
239     ipc_msg_t *ipc_msg = 0;
240     ipc_struct_t *_fs_ipc_struct;
241     struct fd_record_extension *fd_ext;
242     struct fs_request *fr_ptr;
243     off_t ret = 0;
244 
245     if (fd_not_exists(fd))
246         return -EBADF;
247 
248     if (fd_dic[fd]->type != FD_TYPE_FILE)
249         return -ESPIPE;
250     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
251 
252     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
253     ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
254     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
255 
256     fr_ptr->req = FS_REQ_LSEEK;
257     fr_ptr->lseek.fd = fd;
258     fr_ptr->lseek.offset = offset;
259     fr_ptr->lseek.whence = whence;
260 
261     ret = ipc_call(_fs_ipc_struct, ipc_msg);
262     if (ret == 0) {
263         /**
264          * ret == 0 indicates a successful lseek operation,
265          * and we retrieve real offset from fr_ptr(set by server)
266          * to keep the semantic of lseek(2)
267          */
268         ret = fr_ptr->lseek.ret;
269     }
270     ipc_destroy_msg(ipc_msg);
271 
272     return ret;
273 }
274 
chcore_mkdirat(int dirfd,const char * pathname,mode_t mode)275 int chcore_mkdirat(int dirfd, const char *pathname, mode_t mode)
276 {
277     ipc_msg_t *ipc_msg;
278     ipc_struct_t *mounted_fs_ipc_struct;
279     struct fs_request *fr_ptr;
280     struct fsm_request *fsm_req;
281     int ret = 0;
282     int mount_id;
283     char *full_path;
284     char server_path[FS_REQ_PATH_BUF_LEN];
285 
286     /* Check arguments */
287     if (!access_ok(pathname))
288         return -EFAULT;
289 
290     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
291     ret = generate_full_path(dirfd, pathname, &full_path);
292     if (ret)
293         return ret;
294 
295     /* Send IPC to FSM and parse full_path */
296     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
297         free(full_path);
298         return -EINVAL;
299     }
300 
301     /* Send IPC to fs_server */
302     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
303     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
304     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
305 
306     fr_ptr->req = FS_REQ_MKDIR;
307     if (pathcpy(fr_ptr->mkdir.pathname,
308                 FS_REQ_PATH_BUF_LEN,
309                 server_path,
310                 strlen(server_path))
311         != 0) {
312         ipc_destroy_msg(ipc_msg);
313         free(full_path);
314         return -EBADF;
315     }
316     fr_ptr->mkdir.mode = mode;
317     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
318     ipc_destroy_msg(ipc_msg);
319 
320     free(full_path);
321     return ret;
322 }
323 
chcore_unlinkat(int dirfd,const char * pathname,int flags)324 int chcore_unlinkat(int dirfd, const char *pathname, int flags)
325 {
326     ipc_msg_t *ipc_msg;
327     ipc_struct_t *mounted_fs_ipc_struct;
328     struct fs_request *fr_ptr;
329     struct fsm_request *fsm_req;
330     int ret;
331     int mount_id;
332     char *full_path;
333     char *path;
334     char server_path[FS_REQ_PATH_BUF_LEN];
335 
336     /* Check argument */
337     if (!access_ok(pathname))
338         return -EFAULT;
339 
340     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
341     ret = generate_full_path(dirfd, pathname, &full_path);
342     if (ret)
343         return ret;
344 
345     /* Send IPC to FSM and parse full_path */
346     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
347         free(full_path);
348         return -EINVAL;
349     }
350 
351     /* Send IPC to fs_server */
352     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
353     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
354     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
355 
356     if (flags & AT_REMOVEDIR) {
357         fr_ptr->req = FS_REQ_RMDIR;
358         flags &= (~AT_REMOVEDIR);
359         fr_ptr->rmdir.flags = flags;
360         path = fr_ptr->rmdir.pathname;
361     } else {
362         fr_ptr->req = FS_REQ_UNLINK;
363         fr_ptr->unlink.flags = flags;
364         path = fr_ptr->unlink.pathname;
365     }
366     if (pathcpy(path, FS_REQ_PATH_BUF_LEN, server_path, strlen(server_path))
367         != 0) {
368         ipc_destroy_msg(ipc_msg);
369         free(full_path);
370         return -EBADF;
371     }
372     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
373     ipc_destroy_msg(ipc_msg);
374 
375     free(full_path);
376     return ret;
377 }
378 
chcore_symlinkat(const char * target,int newdirfd,const char * linkpath)379 int chcore_symlinkat(const char *target, int newdirfd, const char *linkpath)
380 {
381     ipc_msg_t *ipc_msg;
382     ipc_struct_t *mounted_fs_ipc_struct;
383     struct fs_request *fr_ptr;
384     struct fsm_request *fsm_req;
385     int ret;
386     int mount_id;
387     char *full_path;
388     char server_path[FS_REQ_PATH_BUF_LEN];
389 
390     if (check_path_len(target, FS_REQ_PATH_LEN) != 0)
391         return -EINVAL;
392 
393     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
394     ret = generate_full_path(newdirfd, linkpath, &full_path);
395     if (ret)
396         return ret;
397 
398     /* Send IPC to FSM and parse full_path */
399     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
400         free(full_path);
401         return -EINVAL;
402     }
403 
404     /* Send IPC to fs_server */
405     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
406     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
407     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
408 
409     fr_ptr->req = FS_REQ_SYMLINKAT;
410     if (pathcpy(fr_ptr->symlinkat.linkpath,
411                 FS_REQ_PATH_BUF_LEN,
412                 full_path,
413                 strlen(full_path))
414         != 0) {
415         ipc_destroy_msg(ipc_msg);
416         free(full_path);
417         return -EBADF;
418     }
419     if (pathcpy(fr_ptr->symlinkat.target,
420                 FS_REQ_PATH_BUF_LEN,
421                 target,
422                 strlen(target))
423         != 0) {
424         ipc_destroy_msg(ipc_msg);
425         free(full_path);
426         return -EBADF;
427     }
428     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
429     ipc_destroy_msg(ipc_msg);
430 
431     free(full_path);
432     return ret;
433 }
434 
chcore_getdents64(int fd,char * buf,int count)435 int chcore_getdents64(int fd, char *buf, int count)
436 {
437     ipc_msg_t *ipc_msg = 0;
438     ipc_struct_t *_fs_ipc_struct;
439     struct fd_record_extension *fd_ext;
440     struct fs_request *fr_ptr;
441     int ret = 0, remain = count, cnt;
442 
443     if (fd_not_exists(fd))
444         return -EBADF;
445 
446     BUG_ON(sizeof(struct fs_request) > IPC_SHM_AVAILABLE);
447 
448     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
449 
450     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
451     ipc_msg = ipc_create_msg(_fs_ipc_struct, IPC_SHM_AVAILABLE);
452     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
453     while (remain > 0) {
454         fr_ptr->req = FS_REQ_GETDENTS64;
455         fr_ptr->getdents64.fd = fd;
456         cnt = MIN(remain, IPC_SHM_AVAILABLE);
457         fr_ptr->getdents64.count = cnt;
458         ret = ipc_call(_fs_ipc_struct, ipc_msg);
459         if (ret < 0)
460             goto error;
461         memcpy(buf, ipc_get_msg_data(ipc_msg), ret);
462         buf += ret;
463         remain -= ret;
464         if (ret != cnt)
465             break;
466     }
467     ret = count - remain;
468 error:
469     ipc_destroy_msg(ipc_msg);
470     return ret;
471 }
472 
chcore_file_fcntl(int fd,int cmd,int arg)473 int chcore_file_fcntl(int fd, int cmd, int arg)
474 {
475     ipc_msg_t *ipc_msg = 0;
476     ipc_struct_t *_fs_ipc_struct;
477     struct fd_record_extension *fd_ext, *fd_ext_dup;
478     struct fs_request *fr_ptr;
479     struct lwip_request *lr_ptr;
480     int new_fd, ret = 0;
481 
482     switch (cmd) {
483     case F_DUPFD_CLOEXEC:
484     case F_DUPFD: {
485         new_fd = dup_fd_content(fd, arg);
486         if (new_fd < 0) {
487             goto out_fail;
488         }
489         fd_ext_dup = _new_fd_record_extension();
490         if (fd_ext_dup == NULL) {
491             goto out_free_new_fd;
492         }
493         fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
494         strcpy(fd_ext_dup->path, fd_ext->path);
495         fd_ext_dup->mount_id = fd_ext->mount_id;
496         fd_dic[new_fd]->private_data = (void *)fd_ext_dup;
497         _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
498         if (_fs_ipc_struct == NULL)
499             return -EBADF;
500         ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
501         fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
502         fr_ptr->req = FS_REQ_FCNTL;
503         fr_ptr->fcntl.fcntl_cmd = F_DUPFD;
504         fr_ptr->fcntl.fd = fd;
505         fr_ptr->fcntl.fcntl_arg = new_fd;
506         ret = ipc_call(_fs_ipc_struct, ipc_msg);
507         ipc_destroy_msg(ipc_msg);
508         return new_fd;
509     out_free_new_fd:
510         free_fd(new_fd);
511     out_fail:
512         return ret;
513     }
514     case F_GETFL:
515     case F_SETFL:
516         /* FILE fd */
517         if (fd_dic[fd]->type == FD_TYPE_FILE) {
518             fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
519             if (fd_ext == NULL)
520                 return -EBADF;
521             _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
522             if (_fs_ipc_struct == NULL)
523                 return -EBADF;
524             ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
525             fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
526 
527             fr_ptr->req = FS_REQ_FCNTL;
528             fr_ptr->fcntl.fd = fd;
529             fr_ptr->fcntl.fcntl_cmd = cmd;
530             fr_ptr->fcntl.fcntl_arg = arg;
531 
532             ret = ipc_call(_fs_ipc_struct, ipc_msg);
533             ipc_destroy_msg(ipc_msg);
534 
535             return ret;
536         }
537         warn("does not support F_SETFL for non-fs files\n");
538         return -1;
539     default:
540         return -EINVAL;
541     }
542     return -1;
543 }
544 
chcore_readlinkat(int dirfd,const char * pathname,char * buf,size_t bufsiz)545 int chcore_readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz)
546 {
547     ipc_msg_t *ipc_msg = 0;
548     ipc_struct_t *mounted_fs_ipc_struct;
549     struct fs_request *fr_ptr;
550     struct fsm_request *fsm_req;
551     char *full_path;
552     int ret;
553     int mount_id;
554     char server_path[FS_REQ_PATH_BUF_LEN];
555 
556     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
557     ret = generate_full_path(dirfd, pathname, &full_path);
558     if (ret)
559         return ret;
560 
561     /* Send IPC to FSM and parse full_path */
562     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
563         free(full_path);
564         return -EINVAL;
565     }
566 
567     /* Send IPC to fs_server */
568     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
569     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
570     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
571 
572     fr_ptr->req = FS_REQ_READLINKAT;
573     if (pathcpy(fr_ptr->readlinkat.pathname,
574                 FS_REQ_PATH_BUF_LEN,
575                 server_path,
576                 strlen(server_path))
577         != 0) {
578         ipc_destroy_msg(ipc_msg);
579         free(full_path);
580         return -EBADF;
581     }
582     fr_ptr->readlinkat.bufsiz = bufsiz;
583     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
584 
585     ret = ret > bufsiz ? bufsiz : ret;
586     memcpy(buf, ipc_get_msg_data(ipc_msg), ret);
587     ipc_destroy_msg(ipc_msg);
588 
589     free(full_path);
590     return ret;
591 }
592 
chcore_renameat(int olddirfd,const char * oldpath,int newdirfd,const char * newpath)593 int chcore_renameat(int olddirfd, const char *oldpath, int newdirfd,
594                     const char *newpath)
595 {
596     ipc_msg_t *ipc_msg = 0;
597     ipc_struct_t *mounted_fs_ipc_struct;
598     struct fs_request *fr_ptr;
599     struct fsm_request *fsm_req;
600     char *old_full_path, *new_full_path;
601     int ret, old_mount_id, new_mount_id;
602     char old_server_path[FS_REQ_PATH_BUF_LEN];
603     char new_server_path[FS_REQ_PATH_BUF_LEN];
604 
605     ret = 0;
606 
607     /* Check arguments */
608     if (!access_ok(oldpath) || !access_ok(newpath))
609         return -EFAULT;
610 
611     /* Prepare old/new_full_path for IPC arguments */
612     ret = generate_full_path(olddirfd, oldpath, &old_full_path);
613     if (ret)
614         return ret;
615     ret = generate_full_path(newdirfd, newpath, &new_full_path);
616     if (ret) {
617         free(old_full_path);
618         return ret;
619     }
620 
621     /* Send IPC to FSM and parse old_full_path */
622     if (parse_full_path(old_full_path, &old_mount_id, old_server_path) != 0) {
623         free(old_full_path);
624         free(new_full_path);
625         return -EINVAL;
626     }
627 
628     if (parse_full_path(new_full_path, &new_mount_id, new_server_path) != 0) {
629         free(old_full_path);
630         free(new_full_path);
631         return -EINVAL;
632     }
633 
634     /* Cross-FS renaming is not supported yet */
635     if (old_mount_id != new_mount_id)
636         BUG("Does not support cross-FS rename yet.");
637 
638     /* Send IPC to fs_server */
639     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(old_mount_id);
640     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
641     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
642 
643     fr_ptr->req = FS_REQ_RENAME;
644     pathcpy(fr_ptr->rename.oldpath,
645             FS_REQ_PATH_BUF_LEN,
646             old_server_path,
647             strlen(old_server_path));
648     pathcpy(fr_ptr->rename.newpath,
649             FS_REQ_PATH_BUF_LEN,
650             new_server_path,
651             strlen(new_server_path));
652     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
653     ipc_destroy_msg(ipc_msg);
654 
655     free(old_full_path);
656     free(new_full_path);
657     return ret;
658 }
659 
chcore_vfs_rename(int oldfd,const char * newpath)660 int chcore_vfs_rename(int oldfd, const char *newpath)
661 {
662     int ret = chcore_renameat(
663         AT_FDCWD,
664         ((struct fd_record_extension *)fd_dic[oldfd]->private_data)->path,
665         AT_FDCWD,
666         newpath);
667     return ret;
668 }
669 
chcore_faccessat(int dirfd,const char * pathname,int amode,int flags)670 int chcore_faccessat(int dirfd, const char *pathname, int amode, int flags)
671 {
672     ipc_msg_t *ipc_msg = 0;
673     ipc_struct_t *mounted_fs_ipc_struct;
674     struct fs_request *fr_ptr;
675     struct fsm_request *fsm_req;
676     char *full_path;
677     int ret;
678     int mount_id;
679     char server_path[FS_REQ_PATH_BUF_LEN];
680 
681     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
682     ret = generate_full_path(dirfd, pathname, &full_path);
683     if (ret)
684         return ret;
685 
686     /* Send IPC to FSM and parse full_path */
687     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
688         free(full_path);
689         return -EINVAL;
690     }
691 
692     /* Send IPC to fs_server */
693     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
694     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
695     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
696 
697     fr_ptr->req = FS_REQ_FACCESSAT;
698     fr_ptr->faccessat.flags = flags;
699     fr_ptr->faccessat.mode = amode;
700     if (pathcpy(fr_ptr->faccessat.pathname,
701                 FS_REQ_PATH_BUF_LEN,
702                 server_path,
703                 strlen(server_path))
704         != 0) {
705         ipc_destroy_msg(ipc_msg);
706         free(full_path);
707         return -EBADF;
708     }
709     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
710     ipc_destroy_msg(ipc_msg);
711 
712     free(full_path);
713     return ret;
714 }
715 
chcore_fallocate(int fd,int mode,off_t offset,off_t len)716 int chcore_fallocate(int fd, int mode, off_t offset, off_t len)
717 {
718     ipc_msg_t *ipc_msg = 0;
719     ipc_struct_t *mounted_fs_ipc_struct;
720     struct fd_record_extension *fd_ext;
721     struct fs_request *fr_ptr;
722     int ret = 0;
723 
724     if (fd_not_exists(fd)) {
725         return -EBADF;
726     }
727 
728     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
729 
730     BUG_ON(fd_ext->mount_id < 0);
731     BUG_ON(sizeof(struct fs_request) > IPC_SHM_AVAILABLE); // san check
732 
733     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
734     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
735     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
736 
737     fr_ptr->req = FS_REQ_FALLOCATE;
738     fr_ptr->fallocate.fd = fd;
739     fr_ptr->fallocate.mode = mode;
740     fr_ptr->fallocate.offset = offset;
741     fr_ptr->fallocate.len = len;
742 
743     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
744     ipc_destroy_msg(ipc_msg);
745 
746     return ret;
747 }
748 
749 /*
750  * This function is never being used, all the functionalities
751  * are performed by __xstatxx in syscall_dispatcher.c.
752  */
chcore_statx(int dirfd,const char * pathname,int flags,unsigned int mask,char * buf)753 int chcore_statx(int dirfd, const char *pathname, int flags, unsigned int mask,
754                  char *buf)
755 {
756     BUG("chcore_statx is never being used!");
757     return 0;
758 }
759 
chcore_sync(void)760 int chcore_sync(void)
761 {
762     ipc_msg_t *ipc_msg;
763     struct fsm_request *fsm_req;
764     int ret;
765 
766     ipc_msg = ipc_create_msg(fsm_ipc_struct, sizeof(struct fsm_request));
767     fsm_req = (struct fsm_request *)ipc_get_msg_data(ipc_msg);
768 
769     fsm_req->req = FSM_REQ_SYNC;
770 
771     ret = ipc_call(fsm_ipc_struct, ipc_msg);
772     ipc_destroy_msg(ipc_msg);
773 
774     return ret;
775 }
776 
chcore_fsync(int fd)777 int chcore_fsync(int fd)
778 {
779     ipc_msg_t *ipc_msg;
780     ipc_struct_t *_fs_ipc_struct;
781     struct fd_record_extension *fd_ext;
782     struct fs_request *fr_ptr;
783     int ret;
784 
785     if (fd_not_exists(fd))
786         return -EBADF;
787 
788     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
789 
790     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
791     ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
792     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
793 
794     fr_ptr->req = FS_REQ_FSYNC;
795     fr_ptr->fsync.fd = fd;
796 
797     ret = ipc_call(_fs_ipc_struct, ipc_msg);
798     ipc_destroy_msg(ipc_msg);
799 
800     return ret;
801 }
802 
chcore_fdatasync(int fd)803 int chcore_fdatasync(int fd)
804 {
805     ipc_msg_t *ipc_msg;
806     ipc_struct_t *_fs_ipc_struct;
807     struct fd_record_extension *fd_ext;
808     struct fs_request *fr_ptr;
809     int ret;
810 
811     if (fd_not_exists(fd))
812         return -EBADF;
813 
814     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
815 
816     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
817     ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
818     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
819 
820     fr_ptr->req = FS_REQ_FDATASYNC;
821     fr_ptr->fdatasync.fd = fd;
822 
823     ret = ipc_call(_fs_ipc_struct, ipc_msg);
824     ipc_destroy_msg(ipc_msg);
825 
826     return ret;
827 }
828 
829 /* When open we need to alloco fd number first and call to fs server */
chcore_openat(int dirfd,const char * pathname,int flags,mode_t mode)830 int chcore_openat(int dirfd, const char *pathname, int flags, mode_t mode)
831 {
832     struct fd_record_extension *fd_ext;
833     struct fs_request *fr_ptr;
834     struct fs_request *ret_fr;
835     struct fsm_request *fsm_req;
836     ipc_struct_t *mounted_fs_ipc_struct;
837     int ret;
838     int mount_id;
839     int fd;
840     ipc_msg_t *ipc_msg;
841     char *full_path;
842     char server_path[FS_REQ_PATH_BUF_LEN];
843 
844     /*
845      * Allocate a fd number first,
846      * The fd will be send to fs_server to construct fd->fid mapping
847      */
848     if ((fd = alloc_fd()) < 0)
849         return fd;
850 
851     /* Prepare full_path for IPC arguments, don't forget free(full_path) */
852     ret = generate_full_path(dirfd, pathname, &full_path);
853     if (ret)
854         return ret;
855 
856     /* Send IPC to FSM and parse full_path */
857     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
858         free(full_path);
859         return -EINVAL;
860     }
861 
862     /* Send IPC to fs_server */
863     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
864     // Fill fd record with IPC information */
865     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
866     fd_ext->mount_id = mount_id;
867     if (pathcpy(fd_ext->path, MAX_PATH_BUF_LEN, full_path, strlen(full_path))
868         != 0) {
869         free(full_path);
870         return -EBADF;
871     }
872     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
873     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
874 
875     fr_ptr->req = FS_REQ_OPEN;
876     fr_ptr->open.new_fd = fd;
877     if (pathcpy(fr_ptr->open.pathname,
878                 FS_REQ_PATH_BUF_LEN,
879                 server_path,
880                 strlen(server_path))
881         != 0) {
882         ipc_destroy_msg(ipc_msg);
883         free(full_path);
884         return -EBADF;
885     }
886     fr_ptr->open.flags = flags;
887     fr_ptr->open.mode = mode;
888 
889     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
890 
891     if (ret >= 0) {
892         fd_dic[fd]->type = FD_TYPE_FILE;
893         fd_dic[fd]->fd_op = &file_ops;
894         ret = fd; /* Return fd if succeed */
895     } else {
896         free_fd(fd);
897     }
898 
899     free(full_path);
900     ipc_destroy_msg(ipc_msg);
901 
902     return ret;
903 }
904 
chcore_file_read(int fd,void * buf,size_t count)905 static ssize_t chcore_file_read(int fd, void *buf, size_t count)
906 {
907     ipc_msg_t *ipc_msg;
908     ipc_struct_t *_fs_ipc_struct;
909     struct fd_record_extension *fd_ext;
910     struct fs_request *fr_ptr;
911     ssize_t ret = 0;
912     /**
913      * read(2):
914      * On Linux, read() (and similar system calls) will transfer at most
915      * 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes
916      * actually transferred.  (This is true on both 32-bit and 64-bit
917      * systems.)
918      */
919     ssize_t remain = count <= READ_SIZE_MAX ? (ssize_t)count : READ_SIZE_MAX,
920             cnt;
921 
922     if (fd_not_exists(fd))
923         return -EBADF;
924 
925     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
926 
927     BUG_ON(fd_ext->mount_id < 0);
928     BUG_ON(sizeof(struct fs_request) > IPC_SHM_AVAILABLE); // san check
929     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
930     ipc_msg = ipc_create_msg(_fs_ipc_struct, IPC_SHM_AVAILABLE);
931     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
932     while (remain > 0) {
933         cnt = MIN(remain, IPC_SHM_AVAILABLE);
934         fr_ptr->req = FS_REQ_READ;
935         fr_ptr->read.fd = fd;
936         fr_ptr->read.count = cnt;
937         ret = ipc_call(_fs_ipc_struct, ipc_msg);
938         if (ret > 0)
939             memcpy(buf, ipc_get_msg_data(ipc_msg), ret);
940         buf = (char *)buf + ret;
941         remain -= ret;
942         if (ret != cnt)
943             break;
944     }
945     ret = (ssize_t)count - remain;
946     ipc_destroy_msg(ipc_msg);
947     return ret;
948 }
949 
chcore_file_write(int fd,void * buf,size_t count)950 static ssize_t chcore_file_write(int fd, void *buf, size_t count)
951 {
952     ipc_msg_t *ipc_msg;
953     ipc_struct_t *_fs_ipc_struct;
954     struct fd_record_extension *fd_ext;
955     struct fs_request *fr_ptr;
956     ssize_t ret = 0;
957     /**
958      * see chcore_file_read
959      */
960     ssize_t remain = count <= READ_SIZE_MAX ? (ssize_t)count : READ_SIZE_MAX,
961             cnt;
962 
963     if (fd_not_exists(fd))
964         return -EBADF;
965 
966     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
967 
968     BUG_ON(fd_ext->mount_id < 0);
969     BUG_ON(sizeof(struct fs_request) > IPC_SHM_AVAILABLE); // san check
970     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
971     ipc_msg = ipc_create_msg(_fs_ipc_struct, IPC_SHM_AVAILABLE);
972     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
973     while (remain > 0) {
974         cnt = MIN(remain, FS_BUF_SIZE);
975         fr_ptr->req = FS_REQ_WRITE;
976         fr_ptr->write.fd = fd;
977         fr_ptr->write.count = cnt;
978         ipc_set_msg_data(ipc_msg, buf, sizeof(struct fs_request), cnt);
979         ret = ipc_call(_fs_ipc_struct, ipc_msg);
980         buf = (char *)buf + ret;
981         remain -= ret;
982         if (ret != cnt)
983             break;
984     }
985     ret = (ssize_t)count - remain;
986     ipc_destroy_msg(ipc_msg);
987     return ret;
988 }
989 
chcore_file_close(int fd)990 static int chcore_file_close(int fd)
991 {
992     ipc_msg_t *ipc_msg;
993     ipc_struct_t *_fs_ipc_struct;
994     struct fd_record_extension *fd_ext;
995     struct fs_request *fr_ptr;
996     int ret;
997 
998     if (fd_not_exists(fd))
999         return -EBADF;
1000 
1001     fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
1002 
1003     _fs_ipc_struct = get_ipc_struct_by_mount_id(fd_ext->mount_id);
1004     ipc_msg = ipc_create_msg(_fs_ipc_struct, sizeof(struct fs_request));
1005     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
1006 
1007     fr_ptr->req = FS_REQ_CLOSE;
1008     fr_ptr->close.fd = fd;
1009 
1010     ret = ipc_call(_fs_ipc_struct, ipc_msg);
1011     ipc_destroy_msg(ipc_msg);
1012 
1013     if (ret == 0 || ret == -EBADF) {
1014         if (fd_dic[fd]->private_data)
1015             free(fd_dic[fd]->private_data);
1016         free_fd(fd);
1017     }
1018 
1019     return ret;
1020 }
1021 
chcore_file_ioctl(int fd,unsigned long request,void * arg)1022 static int chcore_file_ioctl(int fd, unsigned long request, void *arg)
1023 {
1024     if (request == TIOCGWINSZ)
1025         return -EBADF;
1026 
1027     WARN("FILE not support ioctl!\n");
1028     return 0;
1029 }
1030 
chcore_mount(const char * special,const char * dir,const char * fstype,unsigned long flags,const void * data)1031 int chcore_mount(const char *special, const char *dir, const char *fstype,
1032                  unsigned long flags, const void *data)
1033 {
1034     ipc_msg_t *ipc_msg;
1035     struct fsm_request *fsm_req;
1036     int ret;
1037 
1038     /* Bind 'fs_cap' and 'mount_point' in FSM */
1039     ipc_msg =
1040         ipc_create_msg_with_cap(fsm_ipc_struct, sizeof(struct fsm_request), 1);
1041     fsm_req = (struct fsm_request *)ipc_get_msg_data(ipc_msg);
1042 
1043     fsm_req->req = FSM_REQ_MOUNT;
1044 
1045     /* fsm_req->path = special (device_name) */
1046     if (pathcpy(fsm_req->path, FS_REQ_PATH_BUF_LEN, special, strlen(special))
1047         != 0) {
1048         ipc_destroy_msg(ipc_msg);
1049         return -EBADF;
1050     }
1051     fsm_req->path_len = strlen(special);
1052 
1053     /* fsm_req->mount_path = dir (mount_point) */
1054     if (pathcpy(fsm_req->mount_path, FS_REQ_PATH_BUF_LEN, dir, strlen(dir))
1055         != 0) {
1056         ipc_destroy_msg(ipc_msg);
1057         return -EBADF;
1058     }
1059     fsm_req->mount_path_len = strlen(dir);
1060 
1061     ret = ipc_call(fsm_ipc_struct, ipc_msg);
1062     ipc_destroy_msg(ipc_msg);
1063 
1064     return ret;
1065 }
1066 
1067 /*
1068  * @args: special is device name, like 'sda1'...
1069  * the 'umount' syscall will call this function to send IPC to FSM
1070  */
chcore_umount(const char * special)1071 int chcore_umount(const char *special)
1072 {
1073     ipc_msg_t *ipc_msg;
1074     struct fsm_request *fsm_req;
1075     int ret;
1076 
1077     ipc_msg =
1078         ipc_create_msg_with_cap(fsm_ipc_struct, sizeof(struct fsm_request), 1);
1079     fsm_req = (struct fsm_request *)ipc_get_msg_data(ipc_msg);
1080 
1081     fsm_req->req = FS_REQ_UMOUNT;
1082 
1083     /* fs_req_data->path = special (device_name) */
1084     if (pathcpy(fsm_req->path, FS_REQ_PATH_BUF_LEN, special, strlen(special))
1085         != 0) {
1086         ipc_destroy_msg(ipc_msg);
1087         return -EBADF;
1088     }
1089     fsm_req->path_len = strlen(special);
1090 
1091     ret = ipc_call(fsm_ipc_struct, ipc_msg);
1092     ipc_destroy_msg(ipc_msg);
1093 
1094     return ret;
1095 }
1096 
1097 /**
1098  * Generic function to request stat information.
1099  * `req` controls which input parameters are used.
1100  * `statbuf` is always the output (struct stat / struct statfs).
1101  * Requests using this function include SYS_fstat, SYS_fstatat,
1102  * SYS_statfs, SYS_fstatfs.
1103  */
__xstatxx(int req,int fd,const char * path,int flags,void * statbuf,size_t bufsize)1104 int __xstatxx(int req, int fd, const char *path, int flags, void *statbuf,
1105               size_t bufsize)
1106 {
1107     ipc_msg_t *ipc_msg;
1108     struct fs_request *fr_ptr;
1109     struct fsm_request *fsm_req;
1110     ipc_struct_t *mounted_fs_ipc_struct;
1111     char *full_path;
1112     int ret, mount_id;
1113     char server_path[FS_REQ_PATH_BUF_LEN];
1114 
1115     if (fd >= 0 && fd <= 2) {
1116         WARN("fake file stat for fd = 0, 1, 2\n");
1117         memset(statbuf, 0, bufsize);
1118         return 0;
1119     }
1120 
1121     /* Prepare full_path for IPC arguments */
1122     ret = generate_full_path(fd, path, &full_path);
1123     if (ret)
1124         return ret;
1125 
1126     /* Send IPC to FSM and parse full_path */
1127     if (parse_full_path(full_path, &mount_id, server_path) != 0) {
1128         free(full_path);
1129         return -EINVAL;
1130     }
1131 
1132     mounted_fs_ipc_struct = get_ipc_struct_by_mount_id(mount_id);
1133     ipc_msg = ipc_create_msg(mounted_fs_ipc_struct, sizeof(struct fs_request));
1134     fr_ptr = (struct fs_request *)ipc_get_msg_data(ipc_msg);
1135 
1136     /* There are 4 type of stat req */
1137     fr_ptr->req = req;
1138 
1139     /*
1140      * Some xstat requests use only `fd` argument but no `path`,
1141      * so if there is no `path`(path==NULL), we should retain `fd` field
1142      */
1143     if (path) {
1144         fr_ptr->stat.fd = fr_ptr->stat.dirfd = AT_FDROOT;
1145         if (pathcpy(fr_ptr->stat.pathname,
1146                     FS_REQ_PATH_BUF_LEN,
1147                     server_path,
1148                     strlen(server_path))
1149             != 0) {
1150             ipc_destroy_msg(ipc_msg);
1151             free(full_path);
1152             return -EBADF;
1153         }
1154     } else {
1155         fr_ptr->stat.fd = fr_ptr->stat.dirfd = fd;
1156         /* `fr_ptr->path` field is not used in this case */
1157     }
1158     fr_ptr->stat.flags = flags;
1159 
1160     ret = ipc_call(mounted_fs_ipc_struct, ipc_msg);
1161     if (ret == 0) {
1162         /* No error */
1163         memcpy(statbuf, ipc_get_msg_data(ipc_msg), bufsize);
1164     }
1165     ipc_destroy_msg(ipc_msg);
1166     if (full_path)
1167         free(full_path);
1168     return ret;
1169 }
1170 
1171 /* FILE */
1172 struct fd_ops file_ops = {
1173     .read = chcore_file_read,
1174     .write = chcore_file_write,
1175     .close = chcore_file_close,
1176     .ioctl = chcore_file_ioctl,
1177     .poll = NULL,
1178     .fcntl = chcore_file_fcntl,
1179 };
1180