1 /*
2  * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <unistd.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <assert.h>
12 #include <sys/param.h>
13 
14 /* realpath logic:
15  * 1. prepend CWD (/)
16  * 2. iterate over components (search until next '/' or end of line)
17  *    - empty, skip the component
18  *    - if it is '.', skip the component
19  *    - if it is '..'
20  *      - and out_level == 0, ??? ('/..')
21  *      - otherwise, reverse-search for '/', set out_pos to that - 1, decrement out_level
22  *    - otherwise, add the component to output, increment out_level
23  */
24 
realpath(const char * file_name,char * resolved_name)25 char * realpath(const char *file_name, char *resolved_name)
26 {
27     char * out_path = resolved_name;
28     if (out_path == NULL) {
29         /* allowed as an extension, allocate memory for the output path */
30         out_path = malloc(PATH_MAX);
31         if (out_path == NULL) {
32             errno = ENOMEM;
33             return NULL;
34         }
35     }
36 
37     /* canonical path starts with / */
38     strlcpy(out_path, "/", PATH_MAX);
39 
40     /* pointers moving over the input and output path buffers */
41     const char* in_ptr = file_name;
42     char* out_ptr = out_path + 1;
43     /* number of path components in the output buffer */
44     size_t out_depth = 0;
45 
46 
47     while (*in_ptr) {
48         /* "path component" is the part between two '/' path separators.
49          * locate the next path component in the input path:
50          */
51         const char* end_of_path_component = strchrnul(in_ptr, '/');
52         size_t path_component_len = end_of_path_component - in_ptr;
53 
54         if (path_component_len == 0 ||
55             (path_component_len == 1 && in_ptr[0] == '.')) {
56             /* empty path component or '.' - nothing to do */
57         } else if (path_component_len == 2 && in_ptr[0] == '.' && in_ptr[1] == '.') {
58             /* '..' - remove one path component from the output */
59             if (out_depth == 0) {
60                 /* nothing to remove */
61             } else if (out_depth == 1) {
62                 /* there is only one path component in output;
63                  * remove it, but keep the leading separator
64                  */
65                 out_ptr = out_path + 1;
66                 *out_ptr = '\0';
67                 out_depth = 0;
68             } else {
69                 /* remove last path component and the separator preceding it */
70                 char * prev_sep = strrchr(out_path, '/');
71                 assert(prev_sep > out_path);  /* this shouldn't be the leading separator */
72                 out_ptr = prev_sep;
73                 *out_ptr = '\0';
74                 --out_depth;
75             }
76         } else {
77             /* copy path component to output; +1 is for the separator  */
78             if (out_ptr - out_path + 1 + path_component_len > PATH_MAX - 1) {
79                 /* output buffer insufficient */
80                 errno = E2BIG;
81                 goto fail;
82             } else {
83                 /* add separator if necessary */
84                 if (out_depth > 0) {
85                     *out_ptr = '/';
86                     ++out_ptr;
87                 }
88                 memcpy(out_ptr, in_ptr, path_component_len);
89                 out_ptr += path_component_len;
90                 *out_ptr = '\0';
91                 ++out_depth;
92             }
93         }
94         /* move input pointer to separator right after this path component */
95         in_ptr += path_component_len;
96         if (*in_ptr != '\0') {
97             /* move past it unless already at the end of the input string */
98             ++in_ptr;
99         }
100     }
101     return out_path;
102 
103 fail:
104     if (resolved_name == NULL) {
105         /* out_path was allocated, free it */
106         free(out_path);
107     }
108     return NULL;
109 }
110 
getcwd(char * buf,size_t size)111 char * getcwd(char *buf, size_t size)
112 {
113     if (buf == NULL) {
114         return strdup("/");
115     }
116     strlcpy(buf, "/", size);
117     return buf;
118 }
119 
chdir(const char * path)120 int chdir(const char *path)
121 {
122     (void) path;
123     errno = ENOSYS;
124     return -1;
125 }
126