qnx: Added more proper support for QNX.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 16 Aug 2017 20:02:54 -0400
changeset 1588 59a7ec36bd8c
parent 1587 3396e6dd19fb
child 1589 e4f75163b60d
qnx: Added more proper support for QNX.
CMakeLists.txt
src/physfs_platform_qnx.c
src/physfs_platforms.h
--- a/CMakeLists.txt	Tue Aug 15 02:08:24 2017 -0400
+++ b/CMakeLists.txt	Wed Aug 16 20:02:54 2017 -0400
@@ -75,6 +75,7 @@
     src/physfs_platform_unix.c
     src/physfs_platform_windows.c
     src/physfs_platform_os2.c
+    src/physfs_platform_qnx.c
     src/physfs_archiver_dir.c
     src/physfs_archiver_unpacked.c
     src/physfs_archiver_grp.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/physfs_platform_qnx.c	Wed Aug 16 20:02:54 2017 -0400
@@ -0,0 +1,169 @@
+/*
+ * QNX support routines for PhysicsFS.
+ *
+ * Please see the file LICENSE.txt in the source's root directory.
+ *
+ *  This file written by Ryan C. Gordon.
+ */
+
+/* This is tested against QNX 7 at the moment. */
+
+#define __PHYSICSFS_INTERNAL__
+#include "physfs_platforms.h"
+
+#ifdef PHYSFS_PLATFORM_QNX
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include "physfs_internal.h"
+
+int __PHYSFS_platformInit(void)
+{
+    return 1;  /* always succeed. */
+} /* __PHYSFS_platformInit */
+
+
+void __PHYSFS_platformDeinit(void)
+{
+    /* no-op */
+} /* __PHYSFS_platformDeinit */
+
+
+char *__PHYSFS_platformCalcBaseDir(const char *argv0)
+{
+    char *retval = (char *) allocator.Malloc(PATH_MAX+1);
+    if (retval == NULL)
+        BAIL(PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+    else
+    {
+        const int fd = open("/proc/self/exefile", O_RDONLY);
+        const ssize_t br = (fd == -1) ? -1 : read(fd, retval, PATH_MAX);
+        char *ptr;
+
+        if (fd != -1)
+            close(fd);
+
+        if ((br < 0) || (br > PATH_MAX))
+        {
+            allocator.Free(retval);
+            BAIL(PHYSFS_ERR_OS_ERROR, NULL);
+        } /* if */
+
+        retval[br] = '\0';
+        ptr = strrchr(retval, '/');
+        if (ptr == NULL)  /* uhoh! */
+        {
+            allocator.Free(retval);
+            BAIL(PHYSFS_ERR_OS_ERROR, NULL);
+        } /* if */
+
+        ptr[1] = '\0';  /* chop off filename, leave dirs and '/' */
+
+        ptr = (char *) allocator.Realloc(retval, (ptr - retval) + 2);
+        if (ptr != NULL)  /* just shrinking buffer; don't care if it failed. */
+            retval = ptr;
+    } /* else */
+
+    return retval;
+} /* __PHYSFS_platformCalcBaseDir */
+
+
+char *__PHYSFS_platformCalcPrefDir(const char *org, const char *app)
+{
+    /* !!! FIXME: this might be wrong; I don't know if there's a better method
+        on QNX, or if it follows XDG specs, etc. */
+    char *retval = NULL;
+    const char *home = __PHYSFS_getUserDir();
+    if (home)
+    {
+        const size_t len = strlen(home) + strlen(app) + 3;
+        retval = (char *) allocator.Malloc(len);
+        BAIL_IF(!retval, PHYSFS_ERR_OUT_OF_MEMORY, NULL);
+        snprintf(retval, len, "%s.%s/", home, app);
+    } /* if */
+    return retval;
+} /* __PHYSFS_platformCalcPrefDir */
+
+
+#if !PHYSFS_NO_CDROM_SUPPORT
+#include <devctl.h>
+#include <sys/dcmd_blk.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+static void checkPathForCD(const char *path, PHYSFS_StringCallback cb, void *d)
+{
+    struct stat statbuf;
+    int fd;
+
+    /* The devctl() thing is QNX-specific. In this case, we query what is
+       probably the mountpoint for the device. statvfs() on that mountpoint
+       will tell use its filesystem type. */
+
+    if ( (stat(path, &statbuf) == 0) &&
+         (S_ISBLK(statbuf.st_mode)) &&
+         ((fd = open(path, O_RDONLY | O_NONBLOCK)) != -1) )
+    {
+        char mnt[256] = { 0 };
+        const int rc = devctl(fd, DCMD_FSYS_MOUNTED_BY, mnt, sizeof (mnt), 0);
+        close(fd);
+        if ( (rc == EOK) && (mnt[0]) )
+        {
+            struct statvfs statvfsbuf;
+            if (statvfs(mnt, &statvfsbuf) == 0)
+            {
+                /* I don't know if this is a complete or accurate list. */
+                const char *fstype = statvfsbuf.f_basetype;
+                const int iscd = ( (strcmp(fstype, "cd") == 0) ||
+                                   (strcmp(fstype, "udf") == 0) );
+                if (iscd)
+                    cb(d, mnt);
+            } /* if */
+        } /* if */
+    } /* if */
+} /* checkPathForCD */
+
+static void checkDevForCD(const char *dev, PHYSFS_StringCallback cb, void *d)
+{
+    size_t len;
+    char *path;
+
+    if (dev[0] == '.')  /* ignore "." and ".." */
+    {
+        if ((dev[1] == '\0') || ((dev[1] == '.') && (dev[2] == '\0')))
+            return;
+    } /* if */
+
+    len = strlen(dev) + 6;
+    path = (char *) __PHYSFS_smallAlloc(len);
+    if (!path)
+        return;  /* oh well. */
+
+    snprintf(path, len, "/dev/%s", dev);
+    checkPathForCD(path, cb, d);
+    __PHYSFS_smallFree(path);
+} /* checkDevForCD */
+#endif /* !PHYSFS_NO_CDROM_SUPPORT */
+
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
+{
+#if !PHYSFS_NO_CDROM_SUPPORT
+    DIR *dirp = opendir("/dev");
+    if (dirp)
+    {
+        struct dirent *dent;
+        while ((dent = readdir(dirp)) != NULL)
+            checkDevForCD(dent->d_name, cb, data);
+        closedir(dirp);
+    } /* if */
+#endif
+} /* __PHYSFS_platformDetectAvailableCDs */
+
+#endif /* PHYSFS_PLATFORM_QNX */
+
+/* end of physfs_platform_qnx.c ... */
+
--- a/src/physfs_platforms.h	Tue Aug 15 02:08:24 2017 -0400
+++ b/src/physfs_platforms.h	Wed Aug 16 20:02:54 2017 -0400
@@ -67,9 +67,7 @@
 #  define PHYSFS_PLATFORM_UNIX 1
 #  define PHYSFS_PLATFORM_POSIX 1
 #elif defined(__QNX__)
-#  define PHYSFS_NO_CDROM_SUPPORT 1  /* !!! FIXME? */
 #  define PHYSFS_PLATFORM_QNX 1
-#  define PHYSFS_PLATFORM_UNIX 1
 #  define PHYSFS_PLATFORM_POSIX 1
 #elif defined(unix) || defined(__unix__)
 #  define PHYSFS_PLATFORM_UNIX 1