Wed Jun 5 15:10:58 1996 Roland McGrath <roland@delasyd.gnu.ai.mit.edu>
[glibc.git] / stdlib / canonicalize.c
blob55ac1bcf1d02a0e8a4e896ab70e837cb672756ee
1 /* Return the canonical absolute name of a given file.
2 Copyright (C) 1996 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
17 not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 Cambridge, MA 02139, USA. */
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <limits.h>
24 #include <sys/stat.h>
25 #include <errno.h>
27 /* Return the canonical absolute name of file NAME. The last file name
28 component need not exist, and may be a symlink to a nonexistent file.
29 If RESOLVED is null, the result is malloc'd; otherwise, if the canonical
30 name is PATH_MAX chars or more, returns null with `errno' set to
31 ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars, returns the
32 name in RESOLVED. */
34 static char *
35 canonicalize (const char *name, char *resolved)
37 struct stat st;
38 const char *p;
39 long int path_max;
40 char *result, *dir, *end;
41 size_t namelen;
43 if (! resolved)
44 path_max = 0;
45 else
47 #ifdef PATH_MAX
48 path_max = PATH_MAX;
49 #else
50 path_max = sysconf (_SC_PATH_MAX);
51 if (path_max <= 0)
52 path_max = 1024;
53 #endif
56 p = strrchr (name, '/');
57 if (!p)
59 dir = (char *) ".";
60 p = name;
62 else
64 if (p++ == name)
65 dir = (char *) "/";
66 else
68 dir = __alloca (p - name);
69 memcpy (dir, name, p - name - 1);
70 dir[p - name] = '\0';
74 result = __canonicalize_directory_name_internal (dir, resolved, path_max);
75 if (!result)
76 return NULL;
78 /* Reconstruct the file name in the canonicalized directory. */
79 namelen = strlen (name);
80 end = strchr (result, '\0');
81 if (resolved)
83 /* Make sure the name is not too long. */
84 if (end - result + namelen > path_max)
86 errno = ENAMETOOLONG;
87 return NULL;
90 else
92 /* The name is dynamically allocated. Extend it. */
93 char *new = realloc (result, end - result + namelen + 1);
94 if (! new)
96 free (result);
97 return NULL;
99 end = new + (end - result);
100 result = new;
102 memcpy (end, name, namelen + 1);
104 while (__lstat (result, &st) == 0 && S_ISLNK (st.st_mode))
106 /* The file is a symlink. Read its contents. */
107 ssize_t n;
108 read_link_contents:
109 n = readlink (result, end,
110 resolved ? result + path_max - end : namelen + 1);
111 if (n < 0)
112 /* Error reading the link contents. */
113 return NULL;
115 if (end[0] == '/')
117 /* Absolute symlink. */
118 if (resolved ? (end + n < result + path_max) : (n < namelen + 1))
120 /* It fit in our buffer, so we have the whole thing. */
121 memcpy (result, end, n);
122 result[n] = '\0';
124 else if (resolved)
126 /* It didn't fit in the remainder of the buffer. Either it
127 fits in the entire buffer, or it doesn't. Copy back the
128 unresolved name onto the canonical directory and try once
129 more. */
130 memcpy (end, name, namelen + 1);
131 n = readlink (result, result, path_max);
132 if (n < 0)
133 return NULL;
134 if (n == path_max)
136 errno = ENAMETOOLONG;
137 return NULL;
139 result[n] = '\0';
141 else
142 /* Try again with a bigger buffer. */
143 goto extend_buffer;
145 /* Check the resolved name for being a symlink too. */
146 continue;
149 if (resolved)
151 if (end + n == result + path_max)
153 /* The link contents we read fill the buffer completely.
154 There may be even more to read, and there is certainly no
155 space for the null terminator. */
156 errno = ENAMETOOLONG;
157 return NULL;
160 else if (n == namelen + 1)
161 extend_buffer:
163 /* The name buffer is dynamically allocated. Extend it. */
164 char *new;
166 /* Copy back the unresolved name onto the canonical directory. */
167 memcpy (end, name, namelen + 1);
169 /* Make more space for readlink. */
170 namelen *= 2;
171 new = realloc (result, end - result + namelen + 1);
172 if (! new)
174 free (result);
175 return NULL;
177 end = new + (end - result);
178 result = new;
180 goto read_link_contents;
183 /* Terminate the string; readlink does not. */
184 end[n] = '\0';
187 return result;
190 weak_alias (canonicalize, realpath)
192 char *
193 canonicalize_file_name (const char *name)
195 return canonicalize (name, NULL);