new xmalloc_readlink_follow() routine to fully expand trailing symlinks
authorPaul Fox <pgf@brightstareng.com>
Thu, 8 Nov 2007 01:11:41 +0000 (01:11 -0000)
committerPaul Fox <pgf@brightstareng.com>
Thu, 8 Nov 2007 01:11:41 +0000 (01:11 -0000)
to get to a "real" file (or directory).

include/libbb.h
libbb/xreadlink.c

index f79d80d7fa74aab750fe2bf4eb91fe84e2c8f553..0170085cbc5962ccfe0b01677c62bf81b43c50b4 100644 (file)
@@ -260,6 +260,7 @@ DIR *warn_opendir(const char *path);
 
 /* UNUSED: char *xmalloc_realpath(const char *path); */
 char *xmalloc_readlink(const char *path);
+char *xmalloc_readlink_follow(const char *path);
 char *xmalloc_readlink_or_warn(const char *path);
 char *xrealloc_getcwd_or_warn(char *cwd);
 
index 98b795f56b1651322acbc462ad515b0e6f5e672a..2f6b1e2372fce1ef2b450352e519f89f3e2a819f 100644 (file)
@@ -32,6 +32,51 @@ char *xmalloc_readlink(const char *path)
        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);