Add oldsiglist.c, netax25/ax25.h, and netrom/netrom.h.
[glibc/history.git] / stdlib / canonicalize.c
blob3617226f0a6c9d38d3457cada16f76cca983e4df
1 /* Return the canonical absolute name of a given file.
2 Copyright (C) 1996, 1997 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
20 #include <assert.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <limits.h>
25 #include <sys/param.h>
26 #include <sys/stat.h>
27 #include <errno.h>
29 /* Return the canonical absolute name of file NAME. A canonical name
30 does not contain any `.', `..' components nor any repeated path
31 separators ('/') or symlinks. All path components must exist. If
32 RESOLVED is null, the result is malloc'd; otherwise, if the
33 canonical name is PATH_MAX chars or more, returns null with `errno'
34 set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
35 returns the name in RESOLVED. If the name cannot be resolved and
36 RESOLVED is non-NULL, it contains the path of the first component
37 that cannot be resolved. If the path can be resolved, RESOLVED
38 holds the same value as the value returned. */
40 static char *
41 canonicalize (const char *name, char *resolved)
43 char *rpath, *dest, *extra_buf = NULL;
44 const char *start, *end, *rpath_limit;
45 long int path_max;
46 int num_links = 0;
48 if (name == NULL || resolved == NULL)
50 /* As per Single Unix Specification V2 we must return an error if
51 either parameter is a null pointer. */
52 __set_errno (EINVAL);
53 return NULL;
56 if (name[0] == '\0')
58 /* As per Single Unix Specification V2 we must return an error if
59 the name argument points to an empty string. */
60 __set_errno (ENOENT);
61 return NULL;
64 #ifdef PATH_MAX
65 path_max = PATH_MAX;
66 #else
67 path_max = pathconf (name, _PC_PATH_MAX);
68 if (path_max <= 0)
69 path_max = 1024;
70 #endif
72 rpath = resolved ? __alloca (path_max) : malloc (path_max);
73 rpath_limit = rpath + path_max;
75 if (name[0] != '/')
77 if (!getcwd (rpath, path_max))
78 goto error;
79 dest = strchr (rpath, '\0');
81 else
83 rpath[0] = '/';
84 dest = rpath + 1;
87 for (start = end = name; *start; start = end)
89 struct stat st;
90 int n;
92 /* Skip sequence of multiple path-separators. */
93 while (*start == '/') ++start;
95 /* Find end of path component. */
96 for (end = start; *end && *end != '/'; ++end);
98 if (end - start == 0)
99 break;
100 else if (strncmp (start, ".", end - start) == 0)
101 /* nothing */;
102 else if (strncmp (start, "..", end - start) == 0)
104 /* Back up to previous component, ignore if at root already. */
105 if (dest > rpath + 1)
106 while ((--dest)[-1] != '/');
108 else
110 size_t new_size;
112 if (dest[-1] != '/')
113 *dest++ = '/';
115 if (dest + (end - start) >= rpath_limit)
117 if (resolved)
119 __set_errno (ENAMETOOLONG);
120 goto error;
122 new_size = rpath_limit - rpath;
123 if (end - start + 1 > path_max)
124 new_size += end - start + 1;
125 else
126 new_size += path_max;
127 rpath = realloc (rpath, new_size);
128 rpath_limit = rpath + new_size;
129 if (!rpath)
130 return NULL;
133 dest = __mempcpy (dest, start, end - start);
134 *dest = '\0';
136 if (__lstat (rpath, &st) < 0)
137 goto error;
139 if (S_ISLNK (st.st_mode))
141 char *buf = __alloca (path_max);
142 size_t len;
144 if (++num_links > MAXSYMLINKS)
146 __set_errno (ELOOP);
147 goto error;
150 n = readlink (rpath, buf, path_max);
151 if (n < 0)
152 goto error;
153 buf[n] = '\0';
155 if (!extra_buf)
156 extra_buf = __alloca (path_max);
158 len = strlen (end);
159 if ((long int) (n + len) >= path_max)
161 __set_errno (ENAMETOOLONG);
162 goto error;
165 /* Careful here, end may be a pointer into extra_buf... */
166 memmove (&extra_buf[n], end, len + 1);
167 memcpy (extra_buf, buf, n);
168 name = end = extra_buf;
170 if (buf[0] == '/')
171 dest = rpath + 1; /* It's an absolute symlink */
172 else
173 /* Back up to previous component, ignore if at root already: */
174 if (dest > rpath + 1)
175 while ((--dest)[-1] != '/');
177 else
178 num_links = 0;
181 if (dest > rpath + 1 && dest[-1] == '/')
182 --dest;
183 *dest = '\0';
185 return resolved ? strcpy (resolved, rpath) : rpath;
187 error:
188 if (resolved)
189 strcpy (resolved, rpath);
190 else
191 free (rpath);
192 return NULL;
194 weak_alias (canonicalize, realpath)
197 char *
198 canonicalize_file_name (const char *name)
200 return canonicalize (name, NULL);