1 /* realpath.c - Return the canonicalized absolute pathname */
2 
3 /* Written 2000 by Werner Almesberger */
4 
5 
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <string.h>
9 #include <limits.h>
10 #include <errno.h>
11 #include <sys/stat.h>
12 
13 
14 /* FIXME: buffer overrun possible, loops forever on cyclic symlinks */
15 
16 
17 /*
18  * Canonical name: never ends with a slash
19  */
20 
resolve_path(char * path,char * result,char * pos)21 static int resolve_path(char *path,char *result,char *pos)
22 {
23     if (*path == '/') {
24 	*result = '/';
25 	pos = result+1;
26 	path++;
27     }
28     *pos = 0;
29     if (!*path) return 0;
30     while (1) {
31 	char *slash;
32 	struct stat st;
33 
34 	slash = *path ? strchr(path,'/') : NULL;
35 	if (slash) *slash = 0;
36 	if (!path[0] || (path[0] == '.' &&
37 	  (!path[1] || (path[1] == '.' && !path[2])))) {
38 	    pos--;
39 	    if (pos != result && path[0] && path[1])
40 		while (*--pos != '/');
41 	}
42 	else {
43 	    strcpy(pos,path);
44 	    if (lstat(result,&st) < 0) return -1;
45 	    if (S_ISLNK(st.st_mode)) {
46 		char buf[PATH_MAX];
47 
48 		if (readlink(result,buf,sizeof(buf)) < 0) return -1;
49 		*pos = 0;
50 		if (slash) {
51 		    *slash = '/';
52 		    strcat(buf,slash);
53 		}
54 		strcpy(path,buf);
55 		if (*path == '/') result[1] = 0;
56 		pos = strchr(result,0);
57 		continue;
58 	    }
59 	    pos = strchr(result,0);
60 	}
61 	if (slash) {
62 	    *pos++ = '/';
63 	    path = slash+1;
64 	}
65 	*pos = 0;
66 	if (!slash) break;
67     }
68     return 0;
69 }
70 
71 
realpath(const char * path,char * resolved_path)72 char *realpath(const char *path,char *resolved_path)
73 {
74     char cwd[PATH_MAX];
75     char *path_copy;
76     int res;
77 
78     if (!*path) {
79 	errno = ENOENT; /* SUSv2 */
80 	return NULL;
81     }
82     if (!getcwd(cwd,sizeof(cwd))) return NULL;
83     strcpy(resolved_path,"/");
84     if (resolve_path(cwd,resolved_path,resolved_path)) return NULL;
85     strcat(resolved_path,"/");
86     path_copy = strdup(path);
87     if (!path_copy) return NULL;
88     res = resolve_path(path_copy,resolved_path,strchr(resolved_path,0));
89     free(path_copy);
90     if (res) return NULL;
91     return resolved_path;
92 }
93