Mercurial > hg > xemacs-beta
comparison src/realpath.c @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | a2f645c6b9f8 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 /* | |
2 * realpath.c -- canonicalize pathname by removing symlinks | |
3 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com> | |
4 * | |
5 | |
6 This file is part of XEmacs. | |
7 | |
8 XEmacs is free software; you can redistribute it and/or modify it | |
9 under the terms of the GNU General Public License as published by the | |
10 Free Software Foundation; either version 2, or (at your option) any | |
11 later version. | |
12 | |
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT | |
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
16 for more details. | |
17 | |
18 You should have received a copy of the GNU General Public License | |
19 along with XEmacs; see the file COPYING. If not, write to | |
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
21 Boston, MA 02111-1307, USA. */ | |
22 | |
23 /* Synched up with: Not in FSF. */ | |
24 | |
25 #ifdef HAVE_CONFIG_H | |
26 #include <config.h> | |
27 #endif | |
28 | |
29 #include <sys/types.h> | |
30 #if defined(HAVE_UNISTD_H) || defined(STDC_HEADERS) | |
31 #include <unistd.h> | |
32 #endif | |
33 #include <stdio.h> | |
34 #include <string.h> | |
35 #ifdef _POSIX_VERSION | |
36 #include <limits.h> /* for PATH_MAX */ | |
37 #else | |
38 #include <sys/param.h> /* for MAXPATHLEN */ | |
39 #endif | |
40 #include <errno.h> | |
41 #ifndef STDC_HEADERS | |
42 extern int errno; | |
43 #endif | |
44 | |
45 #include <sys/stat.h> /* for S_IFLNK */ | |
46 | |
47 #ifndef PATH_MAX | |
48 #ifdef _POSIX_VERSION | |
49 #define PATH_MAX _POSIX_PATH_MAX | |
50 #else | |
51 #ifdef MAXPATHLEN | |
52 #define PATH_MAX MAXPATHLEN | |
53 #else | |
54 #define PATH_MAX 1024 | |
55 #endif | |
56 #endif | |
57 #endif | |
58 | |
59 #define MAX_READLINKS 32 | |
60 | |
61 #ifdef __STDC__ | |
62 char *realpath(const char *path, char resolved_path []) | |
63 #else | |
64 char *realpath(path, resolved_path) | |
65 const char *path; | |
66 char resolved_path []; | |
67 #endif | |
68 { | |
69 char copy_path[PATH_MAX]; | |
70 char link_path[PATH_MAX]; | |
71 char *new_path = resolved_path; | |
72 char *max_path; | |
73 int readlinks = 0; | |
74 int n; | |
75 | |
76 /* Make a copy of the source path since we may need to modify it. */ | |
77 strcpy(copy_path, path); | |
78 path = copy_path; | |
79 max_path = copy_path + PATH_MAX - 2; | |
80 /* If it's a relative pathname use getwd for starters. */ | |
81 if (*path != '/') | |
82 { | |
83 #ifdef HAVE_GETCWD | |
84 getcwd(new_path, PATH_MAX - 1); | |
85 #else | |
86 getwd(new_path); | |
87 #endif | |
88 new_path += strlen(new_path); | |
89 if (new_path[-1] != '/') | |
90 *new_path++ = '/'; | |
91 } | |
92 else | |
93 { | |
94 *new_path++ = '/'; | |
95 path++; | |
96 } | |
97 | |
98 /* Expand each slash-separated pathname component. */ | |
99 while (*path != '\0') | |
100 { | |
101 /* Ignore stray "/". */ | |
102 if (*path == '/') | |
103 { | |
104 path++; | |
105 continue; | |
106 } | |
107 | |
108 if (*path == '.') | |
109 { | |
110 /* Ignore ".". */ | |
111 if (path[1] == '\0' || path[1] == '/') | |
112 { | |
113 path++; | |
114 continue; | |
115 } | |
116 | |
117 if (path[1] == '.') | |
118 { | |
119 if (path[2] == '\0' || path[2] == '/') | |
120 { | |
121 path += 2; | |
122 | |
123 /* Ignore ".." at root. */ | |
124 if (new_path == resolved_path + 1) | |
125 continue; | |
126 | |
127 /* Handle ".." by backing up. */ | |
128 while ((--new_path)[-1] != '/') | |
129 ; | |
130 continue; | |
131 } | |
132 } | |
133 } | |
134 | |
135 /* Safely copy the next pathname component. */ | |
136 while (*path != '\0' && *path != '/') | |
137 { | |
138 if (path > max_path) | |
139 { | |
140 errno = ENAMETOOLONG; | |
141 return NULL; | |
142 } | |
143 *new_path++ = *path++; | |
144 } | |
145 | |
146 #ifdef S_IFLNK | |
147 /* See if latest pathname component is a symlink. */ | |
148 *new_path = '\0'; | |
149 n = readlink(resolved_path, link_path, PATH_MAX - 1); | |
150 | |
151 if (n < 0) | |
152 { | |
153 /* EINVAL means the file exists but isn't a symlink. */ | |
154 if (errno != EINVAL) | |
155 return NULL; | |
156 } | |
157 else | |
158 { | |
159 /* Protect against infinite loops. */ | |
160 if (readlinks++ > MAX_READLINKS) | |
161 { | |
162 errno = ELOOP; | |
163 return NULL; | |
164 } | |
165 | |
166 /* Note: readlink doesn't add the null byte. */ | |
167 link_path[n] = '\0'; | |
168 | |
169 if (*link_path == '/') | |
170 /* Start over for an absolute symlink. */ | |
171 new_path = resolved_path; | |
172 else | |
173 /* Otherwise back up over this component. */ | |
174 while (*(--new_path) != '/') | |
175 ; | |
176 | |
177 /* Safe sex check. */ | |
178 if (strlen(path) + n >= PATH_MAX) | |
179 { | |
180 errno = ENAMETOOLONG; | |
181 return NULL; | |
182 } | |
183 | |
184 /* Insert symlink contents into path. */ | |
185 strcat(link_path, path); | |
186 strcpy(copy_path, link_path); | |
187 path = copy_path; | |
188 } | |
189 #endif /* S_IFLNK */ | |
190 *new_path++ = '/'; | |
191 } | |
192 | |
193 /* Delete trailing slash but don't whomp a lone slash. */ | |
194 if (new_path != resolved_path + 1 && new_path[-1] == '/') | |
195 new_path--; | |
196 | |
197 /* Make sure it's null terminated. */ | |
198 *new_path = '\0'; | |
199 return resolved_path; | |
200 } |