aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/xreadlink.c75
1 files changed, 45 insertions, 30 deletions
diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c
index a18dd0748..2682f6975 100644
--- a/libbb/xreadlink.c
+++ b/libbb/xreadlink.c
@@ -123,7 +123,7 @@ char* FAST_FUNC xmalloc_realpath(const char *path)
123#endif 123#endif
124} 124}
125 125
126char* FAST_FUNC xmalloc_realpath_coreutils(const char *path) 126char* FAST_FUNC xmalloc_realpath_coreutils(char *path)
127{ 127{
128 char *buf; 128 char *buf;
129 129
@@ -137,32 +137,19 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
137 * (the directory must exist). 137 * (the directory must exist).
138 */ 138 */
139 if (!buf && errno == ENOENT) { 139 if (!buf && errno == ENOENT) {
140 char *last_slash = strrchr(path, '/'); 140 char *target, c, *last_slash;
141 if (last_slash) { 141 size_t i;
142 *last_slash++ = '\0'; 142
143 buf = xmalloc_realpath(path); 143 target = xmalloc_readlink(path);
144 if (buf) { 144 if (target) {
145 unsigned len = strlen(buf); 145 /*
146 buf = xrealloc(buf, len + strlen(last_slash) + 2); 146 * $ ln -s /bin/qwe symlink # note: /bin is a link to /usr/bin
147 buf[len++] = '/'; 147 * $ readlink -f symlink
148 strcpy(buf + len, last_slash); 148 * /usr/bin/qwe
149 } 149 * $ realpath symlink
150 } else { 150 * /usr/bin/qwe
151 char *target = xmalloc_readlink(path); 151 */
152 if (target) { 152 if (target[0] != '/') {
153 char *cwd;
154 if (target[0] == '/') {
155 /*
156 * $ ln -s /bin/qwe symlink # note: /bin is a link to /usr/bin
157 * $ readlink -f symlink
158 * /usr/bin/qwe/target_does_not_exist
159 * $ realpath symlink
160 * /usr/bin/qwe/target_does_not_exist
161 */
162 buf = xmalloc_realpath_coreutils(target);
163 free(target);
164 return buf;
165 }
166 /* 153 /*
167 * $ ln -s target_does_not_exist symlink 154 * $ ln -s target_does_not_exist symlink
168 * $ readlink -f symlink 155 * $ readlink -f symlink
@@ -170,13 +157,41 @@ char* FAST_FUNC xmalloc_realpath_coreutils(const char *path)
170 * $ realpath symlink 157 * $ realpath symlink
171 * /CURDIR/target_does_not_exist 158 * /CURDIR/target_does_not_exist
172 */ 159 */
173 cwd = xrealloc_getcwd_or_warn(NULL); 160 char *cwd = xrealloc_getcwd_or_warn(NULL);
174 buf = concat_path_file(cwd, target); 161 char *tmp = concat_path_file(cwd, target);
175 free(cwd); 162 free(cwd);
176 free(target); 163 free(target);
177 return buf; 164 target = tmp;
165 }
166 buf = xmalloc_realpath_coreutils(target);
167 free(target);
168 return buf;
169 }
170
171 /* ignore leading and trailing slashes */
172 while (path[0] == '/' && path[1] == '/')
173 ++path;
174 i = strlen(path) - 1;
175 while (i > 0 && path[i] == '/')
176 i--;
177 c = path[i + 1];
178 path[i + 1] = '\0';
179
180 last_slash = strrchr(path, '/');
181 if (last_slash == path)
182 buf = xstrdup(path);
183 else if (last_slash) {
184 *last_slash = '\0';
185 buf = xmalloc_realpath(path);
186 *last_slash++ = '/';
187 if (buf) {
188 unsigned len = strlen(buf);
189 buf = xrealloc(buf, len + strlen(last_slash) + 2);
190 buf[len++] = '/';
191 strcpy(buf + len, last_slash);
178 } 192 }
179 } 193 }
194 path[i + 1] = c;
180 } 195 }
181 196
182 return buf; 197 return buf;