[physfs] Two Linux problems

Henk Boom henk at henk.ca
Mon Jul 6 12:27:59 EDT 2009


Hi, I'm using physfs to write a tool to create self-contained Lua
executables using a zip file containing Lua modules and data
concatenated with a Lua interpreter, similar to what the LOVE engine
does. I want to say how grateful I am for this library, it's making
this task much easier than it would be otherwise =).

I've had a couple of issues under Linux though, both in
__PHYSFS_platformCalcBaseDir.

First, lstat is used to query /proc/self/exe. On Linux lstat always
returns 0 for sizes of files in /proc, which makes this fail. Also, as
far as I can tell it never removes the basename of the executable from
this path. I've included a patch at the end of this email which seems
to fix the problem on my system. Instead of using lstat it repeatedly
tries readlink with larger and larger buffers.

The other problem that I ran into is that ~ isn't expanded to the
user's home directory during the path search, so if I put the
executable into ~/local/bin/, and put '~local/bin/' in my path rather
than the full path, it's not found.

One last thing, I have a feature request: to have some way to add the
executable to the search path, or at least get the full executable
path. This would be really useful when your executable is itself a zip
file which contains your app's data, as in my case. Right now I'm
faking this by appending the basename of argv[0] to the result of
PHYSFS_getBaseDir(), but that's less reliable than the techniques
physfs already uses internally.

    Henk

Here's the patch for the /proc/self/exe issue. There's one thing I'm
unsure about, in __PHYSFS_platformCurrentDir you free the original
buffer if the pointer returned by realloc is NULL, but looking at
realloc's man page it doesn't say what it does when out of memory, so
I didn't handle it.

diff -rpu orig/physfs-2.0.0/platform/unix.c ./platform/unix.c
--- orig/physfs-2.0.0/platform/unix.c	2009-03-23 01:13:28.000000000 -0400
+++ ./platform/unix.c	2009-07-06 11:57:47.000000000 -0400
@@ -187,7 +187,6 @@ char *__PHYSFS_platformCalcBaseDir(const
     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) )
@@ -198,21 +197,28 @@ char *__PHYSFS_platformCalcBaseDir(const
      *  /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)))
     {
-        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. */
+        int length = 0;
+        char *buf = NULL;
+        int readLength;
+        do
         {
-            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 */
-    } /* if */
+            length = length + 100;
+            buf = (char *) allocator.Realloc(buf, length+1);
+            readLength = buf ? readlink(PROC_SELF_EXE, buf, length+1) : -1;
+        } while(readLength > length);
+        if(readLength > 0)
+        {
+            buf[readLength] = '\0';
+            char *slash = strrchr(buf, '/');
+            if(slash) *(slash + 1) = '\0';
+            retval = buf;
+        }
+        else
+        {
+            if(buf) allocator.Free(buf);
+        }
+    }

     if ((retval == NULL) && (argv0 != NULL))
     {


More information about the physfs mailing list