~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to misc/realpath.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * realpath.c -- canonicalize pathname by removing symlinks
 
3
 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or modify
 
6
 * it under the terms of the GNU Library Public License as published by
 
7
 * the Free Software Foundation; either version 2, or (at your option)
 
8
 * any later version.
 
9
 *
 
10
 * This program 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
 
13
 * GNU Library Public License for more details.
 
14
 */
 
15
 
 
16
#include "system.h"
 
17
 
 
18
#ifndef STDC_HEADERS
 
19
extern int errno;
 
20
#endif
 
21
 
 
22
#ifndef PATH_MAX
 
23
#ifdef _POSIX_VERSION
 
24
#define PATH_MAX _POSIX_PATH_MAX
 
25
#else
 
26
#ifdef MAXPATHLEN
 
27
#define PATH_MAX MAXPATHLEN
 
28
#else
 
29
#define PATH_MAX 1024
 
30
#endif
 
31
#endif
 
32
#endif
 
33
 
 
34
#define MAX_READLINKS 32
 
35
 
 
36
#ifdef __STDC__
 
37
char *realpath(const char *path, char resolved_path [])
 
38
#else
 
39
char *realpath(path, resolved_path)
 
40
const char *path;
 
41
char resolved_path [];
 
42
#endif
 
43
{
 
44
        char copy_path[PATH_MAX];
 
45
        char link_path[PATH_MAX];
 
46
        char *new_path = resolved_path;
 
47
        char *max_path;
 
48
        int readlinks = 0;
 
49
        int n;
 
50
 
 
51
        /* Make a copy of the source path since we may need to modify it. */
 
52
        strcpy(copy_path, path);
 
53
        path = copy_path;
 
54
        max_path = copy_path + PATH_MAX - 2;
 
55
        /* If it's a relative pathname use getwd for starters. */
 
56
        if (*path != '/') {
 
57
#ifdef HAVE_GETCWD
 
58
                getcwd(new_path, PATH_MAX - 1);
 
59
#else
 
60
                getwd(new_path);
 
61
#endif
 
62
                new_path += strlen(new_path);
 
63
                if (new_path[-1] != '/')
 
64
                        *new_path++ = '/';
 
65
        }
 
66
        else {
 
67
                *new_path++ = '/';
 
68
                path++;
 
69
        }
 
70
        /* Expand each slash-separated pathname component. */
 
71
        while (*path != '\0') {
 
72
                /* Ignore stray "/". */
 
73
                if (*path == '/') {
 
74
                        path++;
 
75
                        continue;
 
76
                }
 
77
                if (*path == '.') {
 
78
                        /* Ignore ".". */
 
79
                        if (path[1] == '\0' || path[1] == '/') {
 
80
                                path++;
 
81
                                continue;
 
82
                        }
 
83
                        if (path[1] == '.') {
 
84
                                if (path[2] == '\0' || path[2] == '/') {
 
85
                                        path += 2;
 
86
                                        /* Ignore ".." at root. */
 
87
                                        if (new_path == resolved_path + 1)
 
88
                                                continue;
 
89
                                        /* Handle ".." by backing up. */
 
90
                                        while ((--new_path)[-1] != '/')
 
91
                                                ;
 
92
                                        continue;
 
93
                                }
 
94
                        }
 
95
                }
 
96
                /* Safely copy the next pathname component. */
 
97
                while (*path != '\0' && *path != '/') {
 
98
                        if (path > max_path) {
 
99
                                errno = ENAMETOOLONG;
 
100
                                return NULL;
 
101
                        }
 
102
                        *new_path++ = *path++;
 
103
                }
 
104
#ifdef S_IFLNK
 
105
                /* Protect against infinite loops. */
 
106
                if (readlinks++ > MAX_READLINKS) {
 
107
                        errno = ELOOP;
 
108
                        return NULL;
 
109
                }
 
110
                /* See if latest pathname component is a symlink. */
 
111
                *new_path = '\0';
 
112
                n = readlink(resolved_path, link_path, PATH_MAX - 1);
 
113
                if (n < 0) {
 
114
                        /* EINVAL means the file exists but isn't a symlink. */
 
115
                        if (errno != EINVAL)
 
116
                                return NULL;
 
117
                }
 
118
                else {
 
119
                        /* Note: readlink doesn't add the null byte. */
 
120
                        link_path[n] = '\0';
 
121
                        if (*link_path == '/')
 
122
                                /* Start over for an absolute symlink. */
 
123
                                new_path = resolved_path;
 
124
                        else
 
125
                                /* Otherwise back up over this component. */
 
126
                                while (*(--new_path) != '/')
 
127
                                        ;
 
128
                        /* Safe sex check. */
 
129
                        if (strlen(path) + n >= PATH_MAX) {
 
130
                                errno = ENAMETOOLONG;
 
131
                                return NULL;
 
132
                        }
 
133
                        /* Insert symlink contents into path. */
 
134
                        strcat(link_path, path);
 
135
                        strcpy(copy_path, link_path);
 
136
                        path = copy_path;
 
137
                }
 
138
#endif /* S_IFLNK */
 
139
                *new_path++ = '/';
 
140
        }
 
141
        /* Delete trailing slash but don't whomp a lone slash. */
 
142
        if (new_path != resolved_path + 1 && new_path[-1] == '/')
 
143
                new_path--;
 
144
        /* Make sure it's null terminated. */
 
145
        *new_path = '\0';
 
146
        return resolved_path;
 
147
}