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 * This file contains utils of pathname resolution for tmpfs.
14 *
15 * a path: "/this/is/a/path"
16 * a component: "this", "is", etc.
17 *
18 * In general, a path can be divided into two parts, and we deal with each
19 * part separately. One part is the "final component" part, "path" in the above
20 * example. The other part is the "everything else" part, "/this/is/a" in the
21 * above example.
22 * The reason for such separation is that the final component
23 * usually requires some special care, for example in a call to open() syscall,
24 * whether or not to create the file if it's missing.
25 * The every thing else part is much easier, since we always follow
26 * intermediate symlink when we can, and the everything else part should
27 * only resolve to existing directories.
28 *
29 * The way tmpfs' pathname resolution works is as follows:
30 * 0. walk_component() finds a dentry for one component each time, and update
31 * nd->current by calling step_into() so we get one more level
32 * deeper in the directory tree. It also deals with symlinks and
33 * some other special cases.
34 *
35 * 1. We call walk_prefix() to do a general purpose pathname lookup on the
36 * everything else part. The function will update nd->last in each of its
37 * loop to process one component in the pathname, then call
38 * walk_component() to actually find the dentry of that component name,
39 * in which nd->current will be updated. walk_prefix() only go as far as
40 * setting nd->last to the final component and nd->current to the
41 * parent directory entry of that final component.
42 *
43 * 2. Based on the requirements of different FS system calls, we may take
44 * different approaches to deal with the final component, for example create
45 * it when it's missing. So we wrap this functionality into three wrapper
46 * functions path_parentat(), path_lookupat(), path_openat(). The interfaces
47 * of tmpfs will call these wrappers to do a full pathname lookup and deal
48 * with corner cases.
49 */
50
51 #include "namei.h"
52 #include "chcore/error.h"
53 #include "defs.h"
54 #include "limits.h"
55 #include "stddef.h"
56 #include <errno.h>
57 #include "fcntl.h"
58 #include <string.h>
59
60 /**
61 * @brief length until next '/' or '\0'
62 * @param name pointer to a null terminated string
63 * @return u64 The length of the first component pointed to by name
64 */
get_component_len(const char * name)65 static inline u64 get_component_len(const char *name)
66 {
67 int i = 0;
68 while (name[i] != '\0' && name[i] != '/') {
69 i++;
70 }
71 return i;
72 }
73
init_nd(struct nameidata * nd,unsigned flags)74 static void init_nd(struct nameidata *nd, unsigned flags)
75 {
76 nd->depth = 0;
77 nd->flags = flags;
78 /*
79 * The current implementation of fs_base ensures tmpfs only get absolute
80 * path when dealing with file system requests
81 */
82 nd->current = tmpfs_root_dent;
83 nd->total_link_count = 0;
84 nd->last.str = NULL;
85 }
86
87 /**
88 * @brief Decide whether we can follow the symlink.
89 * @param nd The nameidata structure to check.
90 * @return int 0 if no error, or errno.
91 */
can_follow_symlink(struct nameidata * nd)92 static int can_follow_symlink(struct nameidata *nd)
93 {
94 /* No stack space for the new symlink */
95 if (nd->depth == MAX_STACK_SIZE) {
96 return -ENOMEM;
97 }
98
99 /* Too many symlink encountered */
100 if (nd->total_link_count++ == MAX_SYM_CNT) {
101 return -ELOOP;
102 }
103
104 return 0;
105 }
106
107 /**
108 * @brief update nd->current according to the found dentry
109 * @param nd The nd structure of this path lookup.
110 * @param trailing Indicate whether this is a trailing component, if it is, it
111 * requires some special care.
112 * @param dentry The dentry for nd->current to update to.
113 * @return const char* Return NULL if not a symlink or should not follow, return
114 * the symlink otherwise.
115 */
step_into(struct nameidata * nd,bool trailing,struct dentry * dentry)116 static const char *step_into(struct nameidata *nd, bool trailing,
117 struct dentry *dentry)
118 {
119 int err;
120
121 /*
122 * The dentry is not a symlink or should not be followed
123 */
124 if (dentry->inode->type != FS_SYM
125 /* only the trailing symlink needs to check if it can be followed.
126 always follow non-trailing symlinks */
127 || (trailing && !(nd->flags & ND_FOLLOW))) {
128 nd->current = dentry;
129 return NULL;
130 }
131
132 /* dealing with a symlink now */
133
134 if ((err = can_follow_symlink(nd))) {
135 return CHCORE_ERR_PTR(err);
136 }
137
138 /* symlink is not allowed */
139 if (nd->flags & ND_NO_SYMLINKS) {
140 return CHCORE_ERR_PTR(-ELOOP);
141 }
142
143 /*
144 * we directly return the actual symlink,
145 * without copying it
146 */
147 const char *name = dentry->inode->symlink;
148
149 if (!name) {
150 return NULL;
151 }
152
153 if (*name == '/') {
154 /* Absolute path symlink, jump to root */
155 nd->current = tmpfs_root_dent;
156
157 do {
158 name++;
159 } while (*name == '/');
160 }
161
162 /* we do not update nd->current if the symlink is a relative path. */
163
164 return *name ? name : NULL;
165 }
166
167 /**
168 * @brief Lookup a single component named "nd->last" under the dentry
169 * "nd->current". Find the dentry in walk_component() then call step_into() to
170 * process symlinks and some flags.
171 * @param nd The nd structure representing this path lookup.
172 * @param trailing If this is the trailing component, some special care would be
173 * taken when considering symlinks.
174 * @return const char* Return NULL if no symlink encountered or should/can not
175 * follow, return the symlink to follow it.
176 * @note The result of this function during a pathname lookup will be an updated
177 * nd->current, serving as the parent directory of next component lookup.
178 */
walk_component(struct nameidata * nd,bool trailing)179 static const char *walk_component(struct nameidata *nd, bool trailing)
180 {
181 struct dentry *dentry;
182 struct inode *i_parent;
183
184 i_parent = nd->current->inode;
185 if (i_parent->type != FS_DIR) {
186 return CHCORE_ERR_PTR(-ENOTDIR);
187 }
188
189 /* Find the dentry of the nd->last component under nd->current */
190 dentry =
191 i_parent->d_ops->dirlookup(i_parent, nd->last.str, (int)nd->last.len);
192
193 if (dentry == NULL) {
194 return CHCORE_ERR_PTR(-ENOENT); /* File not exist */
195 }
196
197 return step_into(nd, trailing, dentry);
198 };
199
200 /**
201 * @brief A simple wrapper of walk_component, used when looking up the last
202 * component in the path.
203 * @param nd The nd structure representing this path lookup.
204 * @return const char* Return NULL if no symlink encountered or should/can not
205 * follow, return the symlink to follow it.
206 */
lookup_last(struct nameidata * nd)207 static inline const char *lookup_last(struct nameidata *nd)
208 {
209 if (nd->last.str == NULL) {
210 return NULL;
211 }
212
213 return walk_component(nd, true);
214 }
215
216 /**
217 * @brief lookup the dentry that is to be opened, if it exists, return it.
218 * If it does not exist and O_CREAT is set, creat a regular file of the name
219 * @param nd The nd structure representing this path lookup.
220 * @param open_flags The open flags of this open() syscall.
221 * @return struct dentry* Return the found/created dentry, or NULL if not found.
222 */
lookup_create(struct nameidata * nd,unsigned open_flags)223 static struct dentry *lookup_create(struct nameidata *nd, unsigned open_flags)
224 {
225 struct dentry *dir = nd->current;
226 struct inode *i_dir = dir->inode;
227 struct dentry *dentry;
228 int err;
229
230 dentry = i_dir->d_ops->dirlookup(i_dir, nd->last.str, (int)nd->last.len);
231 if (dentry) {
232 return dentry;
233 }
234
235 /* not found, create it */
236 if (open_flags & O_CREAT) {
237 dentry = i_dir->d_ops->alloc_dentry();
238 if (CHCORE_IS_ERR(dentry)) {
239 return dentry;
240 }
241
242 err =
243 i_dir->d_ops->add_dentry(i_dir, dentry, nd->last.str, nd->last.len);
244 if (err) {
245 i_dir->d_ops->free_dentry(dentry);
246 return CHCORE_ERR_PTR(err);
247 }
248
249 /* we are not currently handling mode in open() */
250 mode_t faked_mode = 0x888;
251
252 int err = i_dir->d_ops->mknod(i_dir, dentry, faked_mode, FS_REG);
253 if (err) {
254 i_dir->d_ops->remove_dentry(i_dir, dentry);
255 i_dir->d_ops->free_dentry(dentry);
256 return CHCORE_ERR_PTR(err);
257 }
258 }
259
260 return dentry;
261 }
262
263 /**
264 * @brief Used in open when looking up the last component of a path, may create
265 * the file if not found.
266 * @param nd The nd structure representing this path lookup.
267 * @param open_flags The open flags of this open() syscall.
268 * @return const char* Return NULL if no symlink encountered or should/can not
269 * follow, return the symlink to follow it.
270 */
lookup_last_open(struct nameidata * nd,unsigned open_flags)271 static const char *lookup_last_open(struct nameidata *nd, unsigned open_flags)
272 {
273 struct dentry *dentry;
274
275 if (!nd->last.str) {
276 return NULL;
277 }
278
279 if ((open_flags & O_CREAT)) {
280 /*
281 * when O_CREAT is set
282 * the path should not have trailing slashes
283 */
284 if (nd->flags & ND_TRAILING_SLASH) {
285 return CHCORE_ERR_PTR(-EISDIR);
286 }
287 }
288
289 dentry = lookup_create(nd, open_flags);
290
291 if (!dentry) {
292 return CHCORE_ERR_PTR(-ENOENT);
293 }
294
295 if (CHCORE_IS_ERR(dentry)) {
296 return (char *)dentry;
297 }
298
299 return step_into(nd, true, dentry);
300 }
301
302 /**
303 * @brief lookup a path except its final component
304 * @param name The full pathname to lookup.
305 * @param nd The nd structure to represent this pathname lookup and to store
306 * state information of this lookup.
307 * @return int 0 on success, errno on failure.
308 */
walk_prefix(const char * name,struct nameidata * nd)309 static int walk_prefix(const char *name, struct nameidata *nd)
310 {
311 int err;
312 if (CHCORE_IS_ERR(name)) {
313 return CHCORE_PTR_ERR(name);
314 }
315
316 while (*name == '/') {
317 name++;
318 }
319
320 if (!*name) {
321 return 0;
322 }
323
324 /* each loop deals with one next path component or get a new symlink */
325 for (;;) {
326 const char *link;
327 u64 component_len = get_component_len(name);
328
329 if (component_len > NAME_MAX) {
330 return -ENAMETOOLONG;
331 }
332
333 err = init_string(&nd->last, name, component_len);
334 if (err) {
335 return err;
336 }
337
338 name += component_len;
339 /* skipping postfixing '/'s till next component name */
340 while (*name == '/') {
341 name++;
342 }
343
344 if (!*name) {
345 if (!nd->depth)
346 /* this is the trailing component */
347 return 0;
348
349 /* pop a link, continue processing */
350 name = nd->stack[--nd->depth];
351 }
352
353 link = walk_component(nd, false);
354
355 /* we have another symlink to process */
356 if (link) {
357 if (CHCORE_IS_ERR(link)) {
358 return CHCORE_PTR_ERR(link);
359 }
360
361 /* checked in step_into() that we have space on stack */
362 nd->stack[nd->depth++] = name; /* store current name */
363 name = link; /* deal with the symlink first */
364 continue;
365 }
366
367 /* next loop requires nd->current to be a directory */
368 if (nd->current->inode->type != FS_DIR) {
369 return -ENOTDIR;
370 }
371 }
372 return 0;
373 }
374
375 /**
376 * @brief Find the parent directory of a given pathname. A very simple wrapper
377 * of walk_prefix(). Used by rename(), unlink(), etc.
378 * @param nd The nd structure representing this lookup.
379 * @param path The full path to lookup.
380 * @param flags Some restriction of this lookup can be passed by the flags
381 * param.
382 * @return int 0 on success, errno on failure.
383 * @return struct dentry* Returned by pointer, the parent directory's
384 * dentry
385 * @return char* Returned in nd->last, the name of the last component of the
386 * pathname.
387 * @note We **DO NOT** call free_string() here because it is normal
388 * for the caller to use nd->last after calling path_parentat() (to
389 * create/rename/remove it under the parent directory). It should be viewed as
390 * the return value of this call.
391 */
path_parentat(struct nameidata * nd,const char * path,unsigned flags,struct dentry ** parent)392 int path_parentat(struct nameidata *nd, const char *path, unsigned flags,
393 struct dentry **parent)
394 {
395 init_nd(nd, flags);
396
397 /*
398 * there's no need to do the checking of trailing slashes here,
399 * since path_parentat never cares about the final component.
400 */
401
402 int err = walk_prefix(path, nd);
403 if (!err) {
404 *parent = nd->current;
405 }
406
407 /*
408 * we **do not** call free_string() here because it is normal for the
409 * caller to use nd->last after calling path_parentat()
410 *
411 * one should also view nd->last as an output of path_parentat()
412 * the subtlety here is annoying but at least we made it clear...
413 */
414 return err;
415 }
416
417 /**
418 * @brief Get the dentry of the full path. Used by: stat(), chmod(), etc.
419 * @param nd The nd structure representing this lookup.
420 * @param path The full path to lookup.
421 * @param flags Some restriction of this lookup can be passed by the flags
422 * param.
423 * @return int 0 on success, errno on failure.
424 * @return struct dentry* Returned by pointer, the final component's
425 * dentry.
426 * @note We call free_string() here because the caller should never use
427 * nd->last after calling path_lookupat().
428 */
path_lookupat(struct nameidata * nd,const char * path,unsigned flags,struct dentry ** dentry)429 int path_lookupat(struct nameidata *nd, const char *path, unsigned flags,
430 struct dentry **dentry)
431 {
432 int err;
433 init_nd(nd, flags);
434
435 if (path[strlen(path) - 1] == '/') {
436 nd->flags |= ND_TRAILING_SLASH | ND_DIRECTORY | ND_FOLLOW;
437 }
438
439 while (!(err = walk_prefix(path, nd)) && (path = lookup_last(nd)) != NULL) {
440 ;
441 }
442
443 /* requiring a directory(because of trailing slashes) */
444 if (!err && (nd->flags & ND_DIRECTORY)
445 && nd->current->inode->type != FS_DIR) {
446 err = -ENOTDIR;
447 }
448
449 if (!err) {
450 *dentry = nd->current;
451 }
452
453 /*
454 * we call free_string() here because the caller should never use
455 * nd->last after calling path_lookupat()
456 *
457 * in other words, the only effective output of path_lookupat
458 * is *dentry when no err is encountered.
459 */
460 free_string(&nd->last);
461 return err;
462 }
463
464 /**
465 * @brief Called by open(), behaviour is determined by open_flags.
466 * We lookup the path, and do special handling of open().
467 * @param nd The nd structure representing this lookup.
468 * @param path The full path to lookup.
469 * @param open_flags The open flags of the open() syscall.
470 * @param flags Some restriction of this lookup can be passed by the flags
471 * param.
472 * @return int 0 on success, errno on failure.
473 * @return struct dentry* Returned by pointer, NULL if not found and cannot be
474 * created, or the found/created dentry.
475 * @note We call free_string() here because the caller should never use
476 * nd->last after calling path_openat().
477 *
478 */
path_openat(struct nameidata * nd,const char * path,unsigned open_flags,unsigned flags,struct dentry ** dentry)479 int path_openat(struct nameidata *nd, const char *path, unsigned open_flags,
480 unsigned flags, struct dentry **dentry)
481 {
482 int err;
483
484 init_nd(nd, flags);
485
486 if (path[strlen(path) - 1] == '/') {
487 nd->flags |= ND_TRAILING_SLASH | ND_DIRECTORY | ND_FOLLOW;
488 }
489
490 /* we don't follow symlinks at end by default */
491 if (!(open_flags & O_NOFOLLOW)) {
492 nd->flags |= ND_FOLLOW;
493 }
494
495 if (open_flags & O_DIRECTORY) {
496 nd->flags |= ND_DIRECTORY;
497 }
498
499 while (!(err = walk_prefix(path, nd))
500 && (path = lookup_last_open(nd, open_flags)) != NULL) {
501 ;
502 }
503
504 if (!err) {
505 struct inode *inode = nd->current->inode;
506
507 /* we can check O_CREAT | O_EXCL here, but fs_base handles it */
508
509 if ((open_flags & O_CREAT) && (inode->type == FS_DIR)) {
510 err = -EISDIR;
511 goto error;
512 }
513
514 if ((nd->flags & ND_DIRECTORY) && !(inode->type == FS_DIR)) {
515 err = -ENOTDIR;
516 goto error;
517 }
518
519 /* we can check O_TRUNCATE here, but fs_base handles it */
520
521 *dentry = nd->current;
522 }
523
524 error:
525 /*
526 * we call free_string() here because the caller should never use
527 * nd->last after calling path_openat(). the reason is the same
528 * as explained in path_lookupat()
529 */
530 free_string(&nd->last);
531 return err;
532 }