]> andersk Git - gssapi-openssh.git/blob - openssh/openbsd-compat/realpath.c
77da14e7c246d570bb8c1dacfc4d6686dc992db9
[gssapi-openssh.git] / openssh / openbsd-compat / realpath.c
1 /*
2  * Copyright (c) 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Jan-Simon Pendry.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32
33 #include "includes.h"
34
35 #if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char *rcsid = "$OpenBSD: realpath.c,v 1.10 2003/08/01 21:04:59 millert Exp $";
39 #endif /* LIBC_SCCS and not lint */
40
41 #include <sys/param.h>
42 #include <sys/stat.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <unistd.h>
49
50 /*
51  * MAXSYMLINKS
52  */
53 #ifndef MAXSYMLINKS
54 #define MAXSYMLINKS 5
55 #endif
56
57 /*
58  * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
59  *
60  * Find the real name of path, by removing all ".", ".." and symlink
61  * components.  Returns (resolved) on success, or (NULL) on failure,
62  * in which case the path which caused trouble is left in (resolved).
63  */
64 char *
65 realpath(const char *path, char *resolved)
66 {
67         struct stat sb;
68         int fd, n, needslash, serrno = 0;
69         char *p, *q, wbuf[MAXPATHLEN], start[MAXPATHLEN];
70         int symlinks = 0;
71
72         /* Save the starting point. */
73         getcwd(start,MAXPATHLEN);       
74         if ((fd = open(".", O_RDONLY)) < 0) {
75                 (void)strlcpy(resolved, ".", MAXPATHLEN);
76                 return (NULL);
77         }
78         close(fd);
79
80         /* Convert "." -> "" to optimize away a needless lstat() and chdir() */
81         if (path[0] == '.' && path[1] == '\0')
82                 path = "";
83
84         /*
85          * Find the dirname and basename from the path to be resolved.
86          * Change directory to the dirname component.
87          * lstat the basename part.
88          *     if it is a symlink, read in the value and loop.
89          *     if it is a directory, then change to that directory.
90          * get the current directory name and append the basename.
91          */
92         strlcpy(resolved, path, MAXPATHLEN);
93 loop:
94         q = strrchr(resolved, '/');
95         if (q != NULL) {
96                 p = q + 1;
97                 if (q == resolved)
98                         q = "/";
99                 else {
100                         do {
101                                 --q;
102                         } while (q > resolved && *q == '/');
103                         q[1] = '\0';
104                         q = resolved;
105                 }
106                 if (chdir(q) < 0)
107                         goto err1;
108         } else
109                 p = resolved;
110
111         /* Deal with the last component. */
112         if (*p != '\0' && lstat(p, &sb) == 0) {
113                 if (S_ISLNK(sb.st_mode)) {
114                         if (++symlinks > MAXSYMLINKS) {
115                                 serrno = ELOOP;
116                                 goto err1;
117                         }
118                         n = readlink(p, resolved, MAXPATHLEN-1);
119                         if (n < 0)
120                                 goto err1;
121                         resolved[n] = '\0';
122                         goto loop;
123                 }
124                 if (S_ISDIR(sb.st_mode)) {
125                         if (chdir(p) < 0)
126                                 goto err1;
127                         p = "";
128                 }
129         }
130
131         /*
132          * Save the last component name and get the full pathname of
133          * the current directory.
134          */
135         (void)strlcpy(wbuf, p, sizeof wbuf);
136         if (getcwd(resolved, MAXPATHLEN) == 0)
137                 goto err1;
138
139         /*
140          * Join the two strings together, ensuring that the right thing
141          * happens if the last component is empty, or the dirname is root.
142          */
143         if (resolved[0] == '/' && resolved[1] == '\0')
144                 needslash = 0;
145         else
146                 needslash = 1;
147
148         if (*wbuf) {
149                 if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) {
150                         serrno = ENAMETOOLONG;
151                         goto err1;
152                 }
153                 if (needslash == 0)
154                         strlcat(resolved, "/", MAXPATHLEN);
155                 strlcat(resolved, wbuf, MAXPATHLEN);
156         }
157
158         /* Go back to where we came from. */
159         if (chdir(start) < 0) {
160                 serrno = errno;
161                 goto err2;
162         }
163         return (resolved);
164
165 err1:   chdir(start);
166 err2:   errno = serrno;
167         return (NULL);
168 }
169 #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */
This page took 0.036266 seconds and 3 git commands to generate.