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 <chcore/syscall.h>
14 #include <chcore-internal/fs_defs.h>
15 #include <chcore/container/list.h>
16 #include <assert.h>
17 #include <chcore/idman.h>
18 #include <malloc.h>
19 #include <chcore/ipc.h>
20 #include <fcntl.h>
21 #include <string.h>
22 #include <chcore-internal/fs_debug.h>
23 #include <pthread.h>
24
25 #include "fs_client_defs.h"
26
27 /* CWD */
28 char cwd_path[MAX_CWD_BUF_LEN];
29 int cwd_len;
30
31 /* For client side mounted fs metadata */
32 cap_t mounted_fs_cap[MAX_MOUNT_ID] = {-1};
33 pthread_key_t mounted_fs_key;
34
get_ipc_struct_by_mount_id(int mount_id)35 ipc_struct_t *get_ipc_struct_by_mount_id(int mount_id)
36 {
37 ipc_struct_t **mounted_fs_ipc_struct;
38 ipc_struct_t *res;
39
40 /* Get thread local */
41 mounted_fs_ipc_struct = pthread_getspecific(mounted_fs_key);
42 if (!mounted_fs_ipc_struct) {
43 mounted_fs_ipc_struct =
44 calloc(1, MAX_MOUNT_ID * sizeof(ipc_struct_t *));
45 BUG_ON(!mounted_fs_ipc_struct);
46 pthread_setspecific(mounted_fs_key, mounted_fs_ipc_struct);
47 }
48
49 /* Find thread local ipc struct, register one if it's not existed */
50 if (!mounted_fs_ipc_struct[mount_id]) {
51 mounted_fs_ipc_struct[mount_id] =
52 ipc_register_client(mounted_fs_cap[mount_id]);
53 BUG_ON(!mounted_fs_ipc_struct[mount_id]);
54 }
55
56 res = mounted_fs_ipc_struct[mount_id];
57
58 /* Do sanity check here. */
59 BUG_ON(!res);
60 return res;
61 }
62
disconnect_mounted_fs(void)63 void disconnect_mounted_fs(void)
64 {
65 int i;
66 ipc_struct_t **mounted_fs_ipc_struct;
67 /* Get thread local */
68 mounted_fs_ipc_struct = pthread_getspecific(mounted_fs_key);
69 if (!mounted_fs_ipc_struct) {
70 return;
71 }
72
73 for (i = 0; i < MAX_MOUNT_ID; i++) {
74 if (mounted_fs_ipc_struct[i]) {
75 ipc_client_close_connection(mounted_fs_ipc_struct[i]);
76 }
77 }
78
79 free(mounted_fs_ipc_struct);
80 }
81
82 /*
83 * Copy path to dst, dst_buf_size is dst's buffer size,
84 * return: -1 means dst_buf_size is not large enough,
85 * 0 mean operation succeed.
86 */
pathcpy(char * dst,size_t dst_buf_size,const char * path,size_t path_len)87 int pathcpy(char *dst, size_t dst_buf_size, const char *path, size_t path_len)
88 {
89 if (dst_buf_size >= path_len + 1) {
90 memset(dst, 0, dst_buf_size);
91 strncpy(dst, path, path_len + 1);
92 } else {
93 return -1;
94 }
95
96 dst[path_len] = '\0';
97 return 0;
98 }
99
100 /* ++++++++++++++++++++++++ File Descriptor Extension ++++++++++++++++++++++ */
101
_new_fd_record_extension(void)102 struct fd_record_extension *_new_fd_record_extension(void)
103 {
104 struct fd_record_extension *ret;
105 ret = (struct fd_record_extension *)calloc(1, sizeof(*ret));
106 if (ret == NULL) {
107 return NULL;
108 }
109 ret->mount_id = -1;
110 return ret;
111 }
112
113 /* ++++++++++++++++++++++++ Path Resolution ++++++++++++++++++++++++++++++++ */
114
path_from_fd(int fd)115 char *path_from_fd(int fd)
116 {
117 struct fd_record_extension *fd_ext;
118
119 if (fd == AT_FDCWD)
120 return cwd_path;
121 else if (fd == AT_FDROOT)
122 return "/";
123
124 fd_ext = (struct fd_record_extension *)fd_dic[fd]->private_data;
125
126 return fd_ext->path;
127 }
128
129 #define PATH_JOIN_SEPERATOR "/"
130
__str_starts_with(const char * str,const char * start)131 static bool __str_starts_with(const char *str, const char *start)
132 {
133 for (;; str++, start++)
134 if (!*start)
135 return true;
136 else if (*str != *start)
137 return false;
138 }
139
__str_ends_with(const char * str,const char * end)140 static bool __str_ends_with(const char *str, const char *end)
141 {
142 int end_len;
143 int str_len;
144
145 if (NULL == str || NULL == end)
146 return false;
147
148 end_len = strlen(end);
149 str_len = strlen(str);
150
151 return str_len < end_len ? false : !strcmp(str + str_len - end_len, end);
152 }
153
path_join(const char * dir,const char * file)154 char *path_join(const char *dir, const char *file)
155 {
156 char *filecopy;
157 int size;
158 char *buf;
159
160 if (!dir)
161 dir = "\0";
162 if (!file)
163 file = "\0";
164
165 size = strlen(dir) + strlen(file) + 2;
166 buf = malloc(size * sizeof(char));
167 if (NULL == buf)
168 return NULL;
169
170 strcpy(buf, dir);
171
172 /* add the sep if necessary */
173 if (!__str_ends_with(dir, PATH_JOIN_SEPERATOR))
174 strcat(buf, PATH_JOIN_SEPERATOR);
175
176 /* remove the sep if necessary */
177 if (__str_starts_with(file, PATH_JOIN_SEPERATOR)) {
178 filecopy = strdup(file);
179 if (NULL == filecopy) {
180 free(buf);
181 return NULL;
182 }
183 strcat(buf, ++filecopy);
184 free(--filecopy);
185 } else {
186 strcat(buf, file);
187 }
188
189 return buf;
190 }
191
192 /* ++++++++++++++++++++++++++ IPC lib for FSM ++++++++++++++++++++++++++++++ */
193
194 /*
195 * ipc_msg is FSM ipc message, and should be created outside
196 * return: fsm_req = ipc_msg_data(ipc_msg)
197 * fsm_req->mount_id = corresponding fs_server mount_id
198 * fsm_req->mount_path/path_len = corresponding fs_server mount_point
199 */
fsm_parse_path_forward(ipc_msg_t * ipc_msg,const char * full_path)200 struct fsm_request *fsm_parse_path_forward(ipc_msg_t *ipc_msg,
201 const char *full_path)
202 {
203 struct fsm_request *fsm_req;
204 ipc_struct_t **mounted_fs_ipc_structs;
205 int mount_id;
206 int ret;
207
208 fsm_req = (struct fsm_request *)ipc_get_msg_data(ipc_msg);
209
210 /* Send ipc to FSM */
211 fsm_req->req = FSM_REQ_PARSE_PATH;
212 if (pathcpy(fsm_req->path, FS_REQ_PATH_BUF_LEN, full_path, strlen(full_path))
213 != 0)
214 return NULL;
215
216 BUG_ON(!fsm_ipc_struct);
217 ret = ipc_call(fsm_ipc_struct, ipc_msg);
218 if (ret < 0) {
219 return NULL;
220 }
221
222 /* Bind mount_id and cap. */
223 mount_id = fsm_req->mount_id;
224 if (fsm_req->new_cap_flag) {
225 assert(mount_id >= 0 && mount_id < MAX_MOUNT_ID);
226 mounted_fs_cap[mount_id] = ipc_get_msg_cap(ipc_msg, 0);
227 }
228
229 assert(mounted_fs_cap[mount_id] > 0);
230
231 /* Call this for initialize tls ipc data, and we don't need return value
232 */
233 get_ipc_struct_by_mount_id(mount_id);
234
235 return fsm_req;
236 }
237
238 /* ++++++++++++++++++++++++++++++++ Others +++++++++++++++++++++++++++++++++ */
239
init_fs_client_side(void)240 void init_fs_client_side(void)
241 {
242 pthread_key_create(&mounted_fs_key, NULL);
243
244 /* Initialize cwd as ROOT */
245 cwd_path[0] = '/';
246 cwd_path[1] = '\0';
247 cwd_len = 1;
248 }
249