/* vi: set sw=4 ts=4: */ /* * xreadlink.c - safe implementation of readlink. * Returns a NULL on failure... */ #include "libbb.h" /* * NOTE: This function returns a malloced char* that you will have to free * yourself. You have been warned. */ char *xmalloc_readlink(const char *path) { enum { GROWBY = 80 }; /* how large we will grow strings by */ char *buf = NULL; int bufsize = 0, readsize = 0; do { bufsize += GROWBY; buf = xrealloc(buf, bufsize); readsize = readlink(path, buf, bufsize); if (readsize == -1) { free(buf); return NULL; } } while (bufsize < readsize + 1); buf[readsize] = '\0'; return buf; } /* * this routine is not the same as realpath(), which canonicalizes * the given path completely. this routine only follows trailing * symlinks until a real file is reached, and returns its name. * intermediate symlinks are not expanded. as above, a malloced * char* is returned, which must be freed. */ char *xmalloc_readlink_follow(const char *path) { char *buf = NULL, *lpc, *linkpath; int bufsize; smallint looping = 0; buf = strdup(path); bufsize = strlen(path) + 1; while(1) { linkpath = xmalloc_readlink(buf); if (!linkpath) { if (errno == EINVAL) /* not a symlink */ return buf; free(buf); return NULL; } if (*linkpath == '/') { free(buf); buf = linkpath; bufsize = strlen(linkpath) + 1; } else { bufsize += strlen(linkpath); if (looping++ > MAXSYMLINKS) { free(linkpath); free(buf); return NULL; } buf = xrealloc(buf, bufsize); lpc = bb_get_last_path_component_strip(buf); strcpy(lpc, linkpath); free(linkpath); } } } char *xmalloc_readlink_or_warn(const char *path) { char *buf = xmalloc_readlink(path); if (!buf) { /* EINVAL => "file: Invalid argument" => puzzled user */ bb_error_msg("%s: cannot read link (not a symlink?)", path); } return buf; } /* UNUSED */ #if 0 char *xmalloc_realpath(const char *path) { #if defined(__GLIBC__) && !defined(__UCLIBC__) /* glibc provides a non-standard extension */ return realpath(path, NULL); #else char buf[PATH_MAX+1]; /* on error returns NULL (xstrdup(NULL) ==NULL) */ return xstrdup(realpath(path, buf)); #endif } #endif