8 |
|
|
9 |
/* |
/* |
10 |
* NOTE: This function returns a malloced char* that you will have to free |
* NOTE: This function returns a malloced char* that you will have to free |
11 |
* yourself. You have been warned. |
* yourself. |
12 |
*/ |
*/ |
13 |
|
char* FAST_FUNC xmalloc_readlink(const char *path) |
|
char *xreadlink(const char *path) |
|
14 |
{ |
{ |
15 |
enum { GROWBY = 80 }; /* how large we will grow strings by */ |
enum { GROWBY = 80 }; /* how large we will grow strings by */ |
16 |
|
|
18 |
int bufsize = 0, readsize = 0; |
int bufsize = 0, readsize = 0; |
19 |
|
|
20 |
do { |
do { |
21 |
buf = xrealloc(buf, bufsize += GROWBY); |
bufsize += GROWBY; |
22 |
readsize = readlink(path, buf, bufsize); /* 1st try */ |
buf = xrealloc(buf, bufsize); |
23 |
|
readsize = readlink(path, buf, bufsize); |
24 |
if (readsize == -1) { |
if (readsize == -1) { |
|
bb_perror_msg("%s", path); |
|
25 |
free(buf); |
free(buf); |
26 |
return NULL; |
return NULL; |
27 |
} |
} |
28 |
} |
} while (bufsize < readsize + 1); |
|
while (bufsize < readsize + 1); |
|
29 |
|
|
30 |
buf[readsize] = '\0'; |
buf[readsize] = '\0'; |
31 |
|
|
32 |
return buf; |
return buf; |
33 |
} |
} |
34 |
|
|
35 |
char *xmalloc_realpath(const char *path) |
/* |
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* FAST_FUNC 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 |
|
linkpath = xmalloc_readlink(buf); |
58 |
|
if (!linkpath) { |
59 |
|
/* not a symlink, or doesn't exist */ |
60 |
|
if (errno == EINVAL || errno == ENOENT) |
61 |
|
return buf; |
62 |
|
goto free_buf_ret_null; |
63 |
|
} |
64 |
|
|
65 |
|
if (!--looping) { |
66 |
|
free(linkpath); |
67 |
|
free_buf_ret_null: |
68 |
|
free(buf); |
69 |
|
return NULL; |
70 |
|
} |
71 |
|
|
72 |
|
if (*linkpath != '/') { |
73 |
|
bufsize += strlen(linkpath); |
74 |
|
buf = xrealloc(buf, bufsize); |
75 |
|
lpc = bb_get_last_path_component_strip(buf); |
76 |
|
strcpy(lpc, linkpath); |
77 |
|
free(linkpath); |
78 |
|
} else { |
79 |
|
free(buf); |
80 |
|
buf = linkpath; |
81 |
|
jump_in: |
82 |
|
bufsize = strlen(buf) + 1; |
83 |
|
} |
84 |
|
} |
85 |
|
} |
86 |
|
|
87 |
|
char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) |
88 |
|
{ |
89 |
|
char *buf = xmalloc_readlink(path); |
90 |
|
if (!buf) { |
91 |
|
/* EINVAL => "file: Invalid argument" => puzzled user */ |
92 |
|
bb_error_msg("%s: cannot read link (not a symlink?)", path); |
93 |
|
} |
94 |
|
return buf; |
95 |
|
} |
96 |
|
|
97 |
|
/* UNUSED */ |
98 |
|
#if 0 |
99 |
|
char* FAST_FUNC xmalloc_realpath(const char *path) |
100 |
{ |
{ |
101 |
#if defined(__GLIBC__) && !defined(__UCLIBC__) |
#if defined(__GLIBC__) && !defined(__UCLIBC__) |
102 |
/* glibc provides a non-standard extension */ |
/* glibc provides a non-standard extension */ |
108 |
return xstrdup(realpath(path, buf)); |
return xstrdup(realpath(path, buf)); |
109 |
#endif |
#endif |
110 |
} |
} |
111 |
|
#endif |