Fixed wrong readlink() usage (lstat() doesn't report dest link size!).
authorRyan C. Gordon <icculus@icculus.org>
Wed, 08 Jul 2009 17:46:48 -0400
changeset 1001 b0c6f2f4f361
parent 999 54f5a2e925ac
child 1002 001380a457a0
Fixed wrong readlink() usage (lstat() doesn't report dest link size!). Thanks to Henk Boom for pointing this out.
src/platform_unix.c
--- a/src/platform_unix.c	Sun Jun 21 17:37:47 2009 -0400
+++ b/src/platform_unix.c	Wed Jul 08 17:46:48 2009 -0400
@@ -198,12 +198,42 @@
 } /* findBinaryInPath */
 
 
+static char *readSymLink(const char *path)
+{
+    ssize_t len = 64;
+    ssize_t rc = -1;
+    char *retval = NULL;
+
+    while (1)
+    {
+         char *ptr = (char *) allocator.Realloc(retval, (size_t) len);
+         if (ptr == NULL)
+             break;   /* out of memory. */
+         retval = ptr;
+
+         rc = readlink(path, retval, len);
+         if (rc == -1)
+             break;  /* not a symlink, i/o error, etc. */
+
+         else if (rc < len)
+         {
+             retval[rc] = '\0';  /* readlink doesn't null-terminate. */
+             return retval;  /* we're good to go. */
+         } /* else if */
+
+         len *= 2;  /* grow buffer, try again. */
+    } /* while */
+
+    if (retval != NULL)
+        allocator.Free(retval);
+    return NULL;
+} /* readSymLink */
+
+
 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
 {
-    const char *PROC_SELF_EXE = "/proc/self/exe";
     char *retval = NULL;
     char *envr = NULL;
-    struct stat stbuf;
 
     /* fast path: default behaviour can handle this. */
     if ( (argv0 != NULL) && (strchr(argv0, '/') != NULL) )
@@ -214,20 +244,12 @@
      *  /proc filesystem, you can get the full path to the current process from
      *  the /proc/self/exe symlink.
      */
-    if ((lstat(PROC_SELF_EXE, &stbuf) != -1) && (S_ISLNK(stbuf.st_mode)))
+    retval = readSymLink("/proc/self/exe");
+    if (retval != NULL)  /* chop off filename. */
     {
-        const size_t len = stbuf.st_size;
-        char *buf = (char *) allocator.Malloc(len+1);
-        if (buf != NULL)  /* if NULL, maybe you'll get lucky later. */
-        {
-            if (readlink(PROC_SELF_EXE, buf, len) != len)
-                allocator.Free(buf);
-            else
-            {
-                buf[len] = '\0';  /* readlink doesn't null-terminate. */
-                retval = buf;  /* we're good to go. */
-            } /* else */
-        } /* if */
+        char *ptr = strrchr(retval, '/');
+        if (ptr != NULL)
+            *ptr = '\0';
     } /* if */
 
     if ((retval == NULL) && (argv0 != NULL))