1
2
3
4
5
6
7
8#include "libbb.h"
9
10
11
12#ifndef MAXSYMLINKS
13# define MAXSYMLINKS 20
14#endif
15
16
17
18
19
20char* FAST_FUNC xmalloc_readlink(const char *path)
21{
22 enum { GROWBY = 80 };
23
24 char *buf = NULL;
25 int bufsize = 0, readsize = 0;
26
27 do {
28 bufsize += GROWBY;
29 buf = xrealloc(buf, bufsize);
30 readsize = readlink(path, buf, bufsize);
31 if (readsize == -1) {
32 free(buf);
33 return NULL;
34 }
35 } while (bufsize < readsize + 1);
36
37 buf[readsize] = '\0';
38
39 return buf;
40}
41
42
43
44
45
46
47
48
49
50
51
52char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
53{
54 char *buf;
55 char *lpc;
56 char *linkpath;
57 int bufsize;
58 int looping = MAXSYMLINKS + 1;
59
60 buf = xstrdup(path);
61 goto jump_in;
62
63 while (1) {
64 linkpath = xmalloc_readlink(buf);
65 if (!linkpath) {
66
67 if (errno == EINVAL || errno == ENOENT)
68 return buf;
69 goto free_buf_ret_null;
70 }
71
72 if (!--looping) {
73 free(linkpath);
74 free_buf_ret_null:
75 free(buf);
76 return NULL;
77 }
78
79 if (*linkpath != '/') {
80 bufsize += strlen(linkpath);
81 buf = xrealloc(buf, bufsize);
82 lpc = bb_get_last_path_component_strip(buf);
83 strcpy(lpc, linkpath);
84 free(linkpath);
85 } else {
86 free(buf);
87 buf = linkpath;
88 jump_in:
89 bufsize = strlen(buf) + 1;
90 }
91 }
92}
93
94char* FAST_FUNC xmalloc_readlink_or_warn(const char *path)
95{
96 char *buf = xmalloc_readlink(path);
97 if (!buf) {
98
99 const char *errmsg = "not a symlink";
100 int err = errno;
101 if (err != EINVAL)
102 errmsg = strerror(err);
103 bb_error_msg("%s: cannot read link: %s", path, errmsg);
104 }
105 return buf;
106}
107
108char* FAST_FUNC xmalloc_realpath(const char *path)
109{
110
111
112
113#if defined(__GLIBC__) && \
114 (!defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 31))
115
116
117 return realpath(path, NULL);
118#else
119 char buf[PATH_MAX+1];
120
121
122 return xstrdup(realpath(path, buf));
123#endif
124}
125
126char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
127{
128 char *buf;
129
130 errno = 0;
131 buf = xmalloc_realpath(path);
132
133
134
135
136
137
138
139 if (!buf && errno == ENOENT) {
140 char *last_slash = strrchr(path, '/');
141 if (last_slash) {
142 *last_slash++ = '\0';
143 buf = xmalloc_realpath(path);
144 if (buf) {
145 unsigned len = strlen(buf);
146 buf = xrealloc(buf, len + strlen(last_slash) + 2);
147 buf[len++] = '/';
148 strcpy(buf + len, last_slash);
149 }
150 } else {
151 char *target = xmalloc_readlink(path);
152 if (target) {
153 char *cwd;
154 if (target[0] == '/') {
155
156
157
158
159
160
161
162 buf = xmalloc_realpath_coreutils(target);
163 free(target);
164 return buf;
165 }
166
167
168
169
170
171
172
173 cwd = xrealloc_getcwd_or_warn(NULL);
174 buf = concat_path_file(cwd, target);
175 free(cwd);
176 free(target);
177 return buf;
178 }
179 }
180 }
181
182 return buf;
183}
184