diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/xreadlink.c | 75 |
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 | ||
126 | char* FAST_FUNC xmalloc_realpath_coreutils(const char *path) | 126 | char* 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; |