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