1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <path_helper.h>
6
up_one_level(char * s)7 static int up_one_level(char *s)
8 {
9 char *tail;
10
11 if (!s)
12 return -1;
13
14 tail = s + strlen(s) - 1;
15 if (*tail == '/')
16 tail--;
17
18 while (*tail != '\0' && *tail != '/')
19 tail--;
20
21 if (*tail == '\0') {
22 return -1;
23 } else {
24 *(tail + 1) = '\0';
25 return 0;
26 }
27 }
28
get_realpath(const char * path,char * resolved_path,unsigned int len)29 char *get_realpath(const char *path, char *resolved_path, unsigned int len)
30 {
31 char *ret, *p = (char *)path, *r = resolved_path;
32
33 if (!path || !r || len < 1)
34 return NULL;
35
36 memset(r, 0, len);
37
38 // deal with heading char
39 if (p[0] != '/') {
40 // relative path
41 ret = getcwd(r, len);
42 if (!ret)
43 return NULL;
44
45 // add tailing '/' if no
46 if (r[strlen(r) - 1] != '/') {
47 r[strlen(r)] = '/';
48 }
49
50 r += strlen(r);
51 } else {
52 // absolute path
53 r[0] = '/';
54 r++;
55 }
56
57 // iterate to exclude '.', '..'. '/'
58 while (*p != '\0') {
59 while (*p == '/')
60 p++;
61 if (*p == '\0')
62 break;
63
64 if (*p == '.') {
65 p++;
66 // end with '.'
67 if (*p == '\0')
68 break;
69
70 if (*p == '.') {
71 // '..' or '../'
72 if ((*(p + 1) != '/') && (*(p + 1) != '\0')) {
73 printf("Invalid path %s\r\n", path);
74 return NULL;
75 } else {
76 // '..' case
77 p++;
78 // if (*p == '/') {
79 if (up_one_level(resolved_path) != 0) {
80 printf("Failed to go up now. Invalid path %s\r\n", path);
81 return NULL;
82 }
83
84 r = resolved_path + strlen(resolved_path);
85 // }
86
87 // end with '.'
88 if (*p == '\0') {
89 break;
90 }
91 }
92 } else {
93 if (*p == '/' || *p == '\0') {
94 p++;
95 } else {
96 // '.xxx' might be hidden file or dir
97 p--;
98 goto copy_valid;
99 }
100 }
101 }
102
103 while (*p == '/')
104 p++;
105 if (*p == '\0')
106 break;
107
108 // if another round of ./.., just continue
109 if (*p == '.')
110 continue;
111
112 copy_valid:
113 // path string may be found now, save to r
114 while ((*p != '/') && (*p != '\0'))
115 *r++ = *p++;
116
117 // add taling '/' if necessary
118 if (*(r - 1) != '/') {
119 *r++ = '/';
120 }
121 }
122
123 /**
124 * considering "cd ../config" for tab key case,
125 * we need set string EOF avoid out of control.
126 */
127 *r = '\0';
128
129 // exclude the tailing '/', just in case it is a file
130 if ((resolved_path[strlen(resolved_path) - 1] == '/') &&
131 (strlen(resolved_path) != 1)) {
132 resolved_path[strlen(resolved_path) - 1] = '\0';
133 }
134
135 return resolved_path;
136 }
137