source: MondoRescue/branches/3.3/mindi-busybox/libbb/xreadlink.c@ 3647

Last change on this file since 3647 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 2.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * xreadlink.c - safe implementation of readlink.
4 * Returns a NULL on failure.
5 *
6 * Licensed under GPLv2, see file LICENSE in this source tree.
7 */
8
9#include "libbb.h"
10
11/* Some systems (eg Hurd) do not have MAXSYMLINKS definition,
12 * set it to some reasonable value if it isn't defined */
13#ifndef MAXSYMLINKS
14# define MAXSYMLINKS 20
15#endif
16
17/*
18 * NOTE: This function returns a malloced char* that you will have to free
19 * yourself.
20 */
21char* FAST_FUNC xmalloc_readlink(const char *path)
22{
23 enum { GROWBY = 80 }; /* how large we will grow strings by */
24
25 char *buf = NULL;
26 int bufsize = 0, readsize = 0;
27
28 do {
29 bufsize += GROWBY;
30 buf = xrealloc(buf, bufsize);
31 readsize = readlink(path, buf, bufsize);
32 if (readsize == -1) {
33 free(buf);
34 return NULL;
35 }
36 } while (bufsize < readsize + 1);
37
38 buf[readsize] = '\0';
39
40 return buf;
41}
42
43/*
44 * This routine is not the same as realpath(), which
45 * canonicalizes the given path completely. This routine only
46 * follows trailing symlinks until a real file is reached and
47 * returns its name. If the path ends in a dangling link or if
48 * the target doesn't exist, the path is returned in any case.
49 * Intermediate symlinks in the path are not expanded -- only
50 * those at the tail.
51 * A malloced char* is returned, which must be freed by the caller.
52 */
53char* FAST_FUNC xmalloc_follow_symlinks(const char *path)
54{
55 char *buf;
56 char *lpc;
57 char *linkpath;
58 int bufsize;
59 int looping = MAXSYMLINKS + 1;
60
61 buf = xstrdup(path);
62 goto jump_in;
63
64 while (1) {
65 linkpath = xmalloc_readlink(buf);
66 if (!linkpath) {
67 /* not a symlink, or doesn't exist */
68 if (errno == EINVAL || errno == ENOENT)
69 return buf;
70 goto free_buf_ret_null;
71 }
72
73 if (!--looping) {
74 free(linkpath);
75 free_buf_ret_null:
76 free(buf);
77 return NULL;
78 }
79
80 if (*linkpath != '/') {
81 bufsize += strlen(linkpath);
82 buf = xrealloc(buf, bufsize);
83 lpc = bb_get_last_path_component_strip(buf);
84 strcpy(lpc, linkpath);
85 free(linkpath);
86 } else {
87 free(buf);
88 buf = linkpath;
89 jump_in:
90 bufsize = strlen(buf) + 1;
91 }
92 }
93}
94
95char* FAST_FUNC xmalloc_readlink_or_warn(const char *path)
96{
97 char *buf = xmalloc_readlink(path);
98 if (!buf) {
99 /* EINVAL => "file: Invalid argument" => puzzled user */
100 const char *errmsg = "not a symlink";
101 int err = errno;
102 if (err != EINVAL)
103 errmsg = strerror(err);
104 bb_error_msg("%s: cannot read link: %s", path, errmsg);
105 }
106 return buf;
107}
108
109char* FAST_FUNC xmalloc_realpath(const char *path)
110{
111/* NB: uclibc also defines __GLIBC__
112 * Therefore the test "if glibc, or uclibc >= 0.9.31" looks a bit weird:
113 */
114#if defined(__GLIBC__) && \
115 (!defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 31))
116 /* glibc provides a non-standard extension */
117 /* new: POSIX.1-2008 specifies this behavior as well */
118 return realpath(path, NULL);
119#else
120 char buf[PATH_MAX+1];
121
122 /* on error returns NULL (xstrdup(NULL) == NULL) */
123 return xstrdup(realpath(path, buf));
124#endif
125}
Note: See TracBrowser for help on using the repository browser.