Added debian/ from 1:1.10.2-1 debian package
[busybox4maemo] / libbb / xreadlink.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  *  xreadlink.c - safe implementation of readlink.
4  *  Returns a NULL on failure...
5  */
6
7 #include "libbb.h"
8
9 /*
10  * NOTE: This function returns a malloced char* that you will have to free
11  * yourself.
12  */
13 char *xmalloc_readlink(const char *path)
14 {
15         enum { GROWBY = 80 }; /* how large we will grow strings by */
16
17         char *buf = NULL;
18         int bufsize = 0, readsize = 0;
19
20         do {
21                 bufsize += GROWBY;
22                 buf = xrealloc(buf, bufsize);
23                 readsize = readlink(path, buf, bufsize);
24                 if (readsize == -1) {
25                         free(buf);
26                         return NULL;
27                 }
28         } while (bufsize < readsize + 1);
29
30         buf[readsize] = '\0';
31
32         return buf;
33 }
34
35 /*
36  * This routine is not the same as realpath(), which
37  * canonicalizes the given path completely. This routine only
38  * follows trailing symlinks until a real file is reached and
39  * returns its name. If the path ends in a dangling link or if
40  * the target doesn't exist, the path is returned in any case.
41  * Intermediate symlinks in the path are not expanded -- only
42  * those at the tail.
43  * A malloced char* is returned, which must be freed by the caller.
44  */
45 char *xmalloc_follow_symlinks(const char *path)
46 {
47         char *buf;
48         char *lpc;
49         char *linkpath;
50         int bufsize;
51         int looping = MAXSYMLINKS + 1;
52
53         buf = xstrdup(path);
54         goto jump_in;
55
56         while (1) {
57
58                 linkpath = xmalloc_readlink(buf);
59                 if (!linkpath) {
60                         /* not a symlink, or doesn't exist */
61                         if (errno == EINVAL || errno == ENOENT)
62                                 return buf;
63                         goto free_buf_ret_null;
64                 }
65
66                 if (!--looping) {
67                         free(linkpath);
68  free_buf_ret_null:
69                         free(buf);
70                         return NULL;
71                 }
72
73                 if (*linkpath != '/') {
74                         bufsize += strlen(linkpath);
75                         buf = xrealloc(buf, bufsize);
76                         lpc = bb_get_last_path_component_strip(buf);
77                         strcpy(lpc, linkpath);
78                         free(linkpath);
79                 } else {
80                         free(buf);
81                         buf = linkpath;
82  jump_in:
83                         bufsize = strlen(buf) + 1;
84                 }
85         }
86 }
87
88 char *xmalloc_readlink_or_warn(const char *path)
89 {
90         char *buf = xmalloc_readlink(path);
91         if (!buf) {
92                 /* EINVAL => "file: Invalid argument" => puzzled user */
93                 bb_error_msg("%s: cannot read link (not a symlink?)", path);
94         }
95         return buf;
96 }
97
98 /* UNUSED */
99 #if 0
100 char *xmalloc_realpath(const char *path)
101 {
102 #if defined(__GLIBC__) && !defined(__UCLIBC__)
103         /* glibc provides a non-standard extension */
104         return realpath(path, NULL);
105 #else
106         char buf[PATH_MAX+1];
107
108         /* on error returns NULL (xstrdup(NULL) ==NULL) */
109         return xstrdup(realpath(path, buf));
110 #endif
111 }
112 #endif