]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - android-sdk/platform-bionic.git/blob - libc/bionic/realpath.c
auto import from //depot/cupcake/@135843
[android-sdk/platform-bionic.git] / libc / bionic / 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. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *      This product includes software developed by the University of
19  *      California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)realpath.c  8.1 (Berkeley) 2/16/94";
39 static char rcsid[] =
40 "$FreeBSD: /repoman/r/ncvs/src/lib/libc/stdlib/realpath.c,v 1.6.2.1 2003/08/03 23:47:39 nectar Exp $";
41 #endif /* LIBC_SCCS and not lint */
43 #include <sys/param.h>
44 #include <sys/stat.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
52 /*
53  * char *realpath(const char *path, char resolved_path[MAXPATHLEN]);
54  *
55  * Find the real name of path, by removing all ".", ".." and symlink
56  * components.  Returns (resolved) on success, or (NULL) on failure,
57  * in which case the path which caused trouble is left in (resolved).
58  */
59 char *
60 realpath(path, resolved)
61         const char *path;
62         char *resolved;
63 {
64         struct stat sb;
65         int fd, n, rootd, serrno;
66         char *p, *q, wbuf[MAXPATHLEN];
67       int symlinks = 0;
69         /* Save the starting point. */
70         if ((fd = open(".", O_RDONLY)) < 0) {
71                 (void)strcpy(resolved, ".");
72                 return (NULL);
73         }
75         /*
76          * Find the dirname and basename from the path to be resolved.
77          * Change directory to the dirname component.
78          * lstat the basename part.
79          *     if it is a symlink, read in the value and loop.
80          *     if it is a directory, then change to that directory.
81          * get the current directory name and append the basename.
82          */
83         (void)strncpy(resolved, path, MAXPATHLEN - 1);
84         resolved[MAXPATHLEN - 1] = '\0';
85 loop:
86         q = strrchr(resolved, '/');
87         if (q != NULL) {
88                 p = q + 1;
89                 if (q == resolved)
90                         q = "/";
91                 else {
92                         do {
93                                 --q;
94                         } while (q > resolved && *q == '/');
95                         q[1] = '\0';
96                         q = resolved;
97                 }
98                 if (chdir(q) < 0)
99                         goto err1;
100         } else
101                 p = resolved;
103         /* Deal with the last component. */
104         if (*p != '\0' && lstat(p, &sb) == 0) {
105                 if (S_ISLNK(sb.st_mode)) {
106                       if (++symlinks > MAXSYMLINKS) {
107                               errno = ELOOP;
108                               goto err1;
109                       }
110                         n = readlink(p, resolved, MAXPATHLEN - 1);
111                         if (n < 0)
112                                 goto err1;
113                         resolved[n] = '\0';
114                         goto loop;
115                 }
116                 if (S_ISDIR(sb.st_mode)) {
117                         if (chdir(p) < 0)
118                                 goto err1;
119                         p = "";
120                 }
121         }
123         /*
124          * Save the last component name and get the full pathname of
125          * the current directory.
126          */
127         (void)strcpy(wbuf, p);
128         if (getcwd(resolved, MAXPATHLEN) == 0)
129                 goto err1;
131         /*
132          * Join the two strings together, ensuring that the right thing
133          * happens if the last component is empty, or the dirname is root.
134          */
135         if (resolved[0] == '/' && resolved[1] == '\0')
136                 rootd = 1;
137         else
138                 rootd = 0;
140         if (*wbuf) {
141                 if (strlen(resolved) + strlen(wbuf) + (1-rootd) + 1 >
142                     MAXPATHLEN) {
143                         errno = ENAMETOOLONG;
144                         goto err1;
145                 }
146                 if (rootd == 0)
147                         (void)strcat(resolved, "/");
148                 (void)strcat(resolved, wbuf);
149         }
151         /* Go back to where we came from. */
152         if (fchdir(fd) < 0) {
153                 serrno = errno;
154                 goto err2;
155         }
157         /* It's okay if the close fails, what's an fd more or less? */
158         (void)close(fd);
159         return (resolved);
161 err1:   serrno = errno;
162         (void)fchdir(fd);
163 err2:   (void)close(fd);
164         errno = serrno;
165         return (NULL);