Rename get_plugin_dir() for consistency
[metze/wireshark/wip.git] / wsutil / filesystem.c
index 181e5f44efb83cf64df5348e04ee0a2d038bb59c..fd0964975a69c401d8e3586efd4d38d457bc8e06 100644 (file)
@@ -1,8 +1,6 @@
 /* filesystem.c
  * Filesystem utility routines
  *
- * $Id$
- *
  * Wireshark - Network traffic analyzer
  * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
@@ -22,7 +20,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#include "config.h"
+#include <config.h>
 
 /*
  * Required with GNU libc to get dladdr().
  */
 #define _GNU_SOURCE
 
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-
 #include <stdio.h>
-#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 
 #include <glib.h>
 
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
 #ifdef _WIN32
 #include <windows.h>
 #include <tchar.h>
 #endif /* _WIN32 */
 
 #include "filesystem.h"
-#include <wsutil/report_err.h>
+#include <wsutil/report_message.h>
 #include <wsutil/privileges.h>
 #include <wsutil/file_util.h>
+#include <wsutil/utf8_entities.h>
 
 #include <wiretap/wtap.h>   /* for WTAP_ERR_SHORT_WRITE */
 
 #define PROFILES_DIR    "profiles"
 #define PLUGINS_DIR_NAME    "plugins"
-
-#define U3_MY_CAPTURES  "\\My Captures"
+#define PROFILES_INFO_NAME  "profile_files.txt"
 
 char *persconffile_dir = NULL;
 char *persdatafile_dir = NULL;
@@ -201,25 +182,6 @@ get_dirname(char *path)
  *  to be a directory.
  */
 
-/*
- * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
- * define them either.)
- *
- * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
- */
-#ifndef S_ISREG
-#define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
-#endif
-#ifndef S_IFIFO
-#define S_IFIFO _S_IFIFO
-#endif
-#ifndef S_ISFIFO
-#define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
-#endif
-#ifndef S_ISDIR
-#define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
-#endif
-
 int
 test_for_directory(const char *path)
 {
@@ -393,7 +355,8 @@ get_executable_path(void)
      * XXX - are there OS versions that support "exe" but not "self"?
      */
     struct utsname name;
-    static char executable_path[PATH_MAX];
+    static char executable_path[PATH_MAX + 1];
+    ssize_t r;
 
     if (uname(&name) == -1)
         return NULL;
@@ -404,8 +367,9 @@ get_executable_path(void)
         strcmp(name.release, "2.1") == 0 ||
         strncmp(name.release, "2.1.", 4) == 0)
         return NULL; /* Linux 2.0.x or 2.1.x */
-    if (readlink("/proc/self/exe", executable_path, sizeof executable_path) == -1)
+    if ((r = readlink("/proc/self/exe", executable_path, PATH_MAX)) == -1)
         return NULL;
+    executable_path[r] = '\0';
     return executable_path;
 #elif defined(__FreeBSD__) && defined(KERN_PROC_PATHNAME)
     /*
@@ -443,10 +407,12 @@ get_executable_path(void)
      * XXX - are there OS versions that support "exe" but not "curproc"
      * or "self"?  Are there any that support "self" but not "curproc"?
      */
-    static char executable_path[PATH_MAX];
+    static char executable_path[PATH_MAX + 1];
+    ssize_t r;
 
-    if (readlink("/proc/curproc/exe", executable_path, sizeof executable_path) == -1)
+    if ((r = readlink("/proc/curproc/exe", executable_path, PATH_MAX)) == -1)
         return NULL;
+    executable_path[r] = '\0';
     return executable_path;
 #elif defined(__DragonFly__)
     /*
@@ -455,10 +421,12 @@ get_executable_path(void)
      * instead; it appears to be supported by all versions of DragonFly
      * BSD.
      */
-    static char executable_path[PATH_MAX];
+    static char executable_path[PATH_MAX + 1];
+    ssize_t r;
 
-    if (readlink("/proc/curproc/file", executable_path, sizeof executable_path) == -1)
+    if ((r = readlink("/proc/curproc/file", executable_path, PATH_MAX)) == -1)
         return NULL;
+    executable_path[r] = '\0';
     return executable_path;
 #elif (defined(sun) || defined(__sun)) && defined(HAVE_GETEXECNAME)
     /*
@@ -486,7 +454,7 @@ init_progfile_dir(const char *arg0
 #ifdef _WIN32
     _U_
 #endif
-, int (*main_addr)(int, char **)
+, int (*function_addr)(int, char **)
 #if defined(_WIN32) || !defined(HAVE_DLADDR)
     _U_
 #endif
@@ -506,8 +474,7 @@ init_progfile_dir(const char *arg0
      */
     if (GetModuleFileName(NULL, prog_pathname_w, G_N_ELEMENTS(prog_pathname_w)) != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
         /*
-         * XXX - Should we use g_utf16_to_utf8(), as in
-         * getenv_utf8()?
+         * XXX - Should we use g_utf16_to_utf8()?
          */
         prog_pathname = utf_16to8(prog_pathname_w);
         /*
@@ -560,8 +527,8 @@ init_progfile_dir(const char *arg0
     char *prog_pathname;
     char *curdir;
     long path_max;
-    char *pathstr;
-    char *path_start, *path_end;
+    const char *pathstr;
+    const char *path_start, *path_end;
     size_t path_component_len, path_len;
     char *retstr;
     char *path;
@@ -576,13 +543,13 @@ init_progfile_dir(const char *arg0
      * set, causes us to look for plugins and the like in the build
      * directory.)
      */
-    if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
+    if (g_getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
         && !started_with_special_privs())
         running_in_build_directory_flag = TRUE;
 
     execname = get_executable_path();
 #ifdef HAVE_DLADDR
-    if (main_addr != NULL && execname == NULL) {
+    if (function_addr != NULL && execname == NULL) {
         /*
          * Try to use dladdr() to find the pathname of the executable.
          * dladdr() is not guaranteed to give you anything better than
@@ -592,8 +559,11 @@ init_progfile_dir(const char *arg0
          * path and obviate the need for us to determine the absolute
          * path.
          */
-        if (dladdr((void *)main_addr, &info))
+DIAG_OFF(pedantic)
+        if (dladdr((void *)function_addr, &info)) {
+DIAG_ON(pedantic)
             execname = info.dli_fname;
+        }
     }
 #endif
     if (execname == NULL) {
@@ -653,7 +623,7 @@ init_progfile_dir(const char *arg0
          * that's executable.
          */
         prog_pathname = NULL;   /* haven't found it yet */
-        pathstr = getenv("PATH");
+        pathstr = g_getenv("PATH");
         path_start = pathstr;
         if (path_start != NULL) {
             while (*path_start != '\0') {
@@ -749,9 +719,23 @@ init_progfile_dir(const char *arg0
                 if (!started_with_special_privs())
                     running_in_build_directory_flag = TRUE;
             }
+            else if (!started_with_special_privs()) {
+                /*
+                 * Check for the CMake output directory. As people may name
+                 * their directories "run" (really?), also check for the
+                 * CMakeCache.txt file before assuming a CMake output dir.
+                 */
+                if (strcmp(dir_end, "/run") == 0) {
+                    gchar *cmake_file;
+                    cmake_file = g_strdup_printf("%.*s/CMakeCache.txt",
+                                                 (int)(dir_end - prog_pathname),
+                                                 prog_pathname);
+                    if (file_exists(cmake_file))
+                        running_in_build_directory_flag = TRUE;
+                    g_free(cmake_file);
+                }
 #ifdef __APPLE__
-            else {
-                if (!started_with_special_privs()) {
+                if (!running_in_build_directory_flag) {
                     /*
                      * Scan up the path looking for a component
                      * named "Contents".  If we find it, we assume
@@ -793,8 +777,8 @@ init_progfile_dir(const char *arg0
                         p--;
                     }
                 }
-            }
 #endif
+            }
         }
 
         /*
@@ -860,9 +844,6 @@ get_progfile_dir(void)
 const char *
 get_datafile_dir(void)
 {
-#ifdef _WIN32
-    char *u3deviceexecpath;
-#endif
     static const char *datafile_dir = NULL;
 
     if (datafile_dir != NULL)
@@ -870,39 +851,27 @@ get_datafile_dir(void)
 
 #ifdef _WIN32
     /*
-     * See if we are running in a U3 environment.
+     * Do we have the pathname of the program?  If so, assume we're
+     * running an installed version of the program.  If we fail,
+     * we don't change "datafile_dir", and thus end up using the
+     * default.
+     *
+     * XXX - does NSIS put the installation directory into
+     * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"?
+     * If so, perhaps we should read that from the registry,
+     * instead.
      */
-    u3deviceexecpath = getenv_utf8("U3_DEVICE_EXEC_PATH");
-
-    if (u3deviceexecpath != NULL) {
+    if (progfile_dir != NULL) {
         /*
-         * We are; use the U3 device executable path.
+         * Yes, we do; use that.
          */
-        datafile_dir = u3deviceexecpath;
+        datafile_dir = progfile_dir;
     } else {
         /*
-         * Do we have the pathname of the program?  If so, assume we're
-         * running an installed version of the program.  If we fail,
-         * we don't change "datafile_dir", and thus end up using the
-         * default.
-         *
-         * XXX - does NSIS put the installation directory into
-         * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"?
-         * If so, perhaps we should read that from the registry,
-         * instead.
+         * No, we don't.
+         * Fall back on the default installation directory.
          */
-        if (progfile_dir != NULL) {
-            /*
-             * Yes, we do; use that.
-             */
-            datafile_dir = progfile_dir;
-        } else {
-            /*
-             * No, we don't.
-             * Fall back on the default installation directory.
-             */
-            datafile_dir = "C:\\Program Files\\Wireshark\\";
-        }
+        datafile_dir = "C:\\Program Files\\Wireshark\\";
     }
 #else
 
@@ -918,16 +887,29 @@ get_datafile_dir(void)
          * Use the top-level source directory as the datafile directory
          * because most of our data files (radius/, COPYING) are there.
          */
-        datafile_dir = g_strdup(TOP_SRCDIR);
+#ifdef TOP_SRCDIR
+        /*
+         * When TOP_SRCDIR is defined, assume autotools where files are not
+         * copied to the build directory. This fallback location is relied on by
+         * wslua_get_actual_filename().
+         */
+        datafile_dir = TOP_SRCDIR;
+#else
+        /*
+         * Otherwise assume CMake. Here, data files (console.lua, radius/, etc.)
+         * are copied to the build directory during the build.
+         */
+        datafile_dir = BUILD_TIME_DATAFILE_DIR;
+#endif
         return datafile_dir;
     } else {
-        if (getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) {
+        if (g_getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) {
             /*
              * The user specified a different directory for data files
              * and we aren't running with special privileges.
              * XXX - We might be able to dispense with the priv check
              */
-            datafile_dir = g_strdup(getenv("WIRESHARK_DATA_DIR"));
+            datafile_dir = g_strdup(g_getenv("WIRESHARK_DATA_DIR"));
         }
 #ifdef __APPLE__
         /*
@@ -953,61 +935,65 @@ get_datafile_dir(void)
     return datafile_dir;
 }
 
-#ifdef HAVE_PYTHON
+#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
 /*
- * Find the directory where the python dissectors are stored.
+ * Find the directory where the plugins are stored.
  *
- * On Windows, we use the "py_dissector" subdirectory of the datafile directory.
+ * On Windows, we use the plugin\{VERSION} subdirectory of the datafile
+ * directory, where {VERSION} is the version number of this version of
+ * Wireshark.
  *
- * On UN*X, we use the PYTHON_DIR value supplied by the configure
- * script, unless we think we're being run from the build directory,
- * in which case we use the "py_dissector" subdirectory of the datafile directory.
+ * On UN*X:
  *
- * In both cases, we then use the subdirectory of that directory whose
- * name is the version number.
+ *    if we appear to be run from the build directory, we use the
+ *    "plugin" subdirectory of the datafile directory;
  *
- * XXX - if we think we're being run from the build directory, perhaps we
- * should have the plugin code not look in the version subdirectory
- * of the plugin directory, but look in all of the subdirectories
- * of the plugin directory, so it can just fetch the plugins built
- * as part of the build process.
+ *    otherwise, if the WIRESHARK_PLUGIN_DIR environment variable is
+ *    set and we aren't running with special privileges, we use the
+ *    value of that environment variable;
+ *
+ *    otherwise, if we're running from an app bundle in macOS, we
+ *    use the Contents/PlugIns/wireshark subdirectory of the app bundle;
+ *
+ *    otherwise, we use the PLUGIN_DIR value supplied by the
+ *    configure script.
  */
-static const char *wspython_dir = NULL;
+static char *plugin_dir = NULL;
+static char *plugin_pers_dir = NULL;
 
 static void
-init_wspython_dir(void)
+init_plugin_dir(void)
 {
 #ifdef _WIN32
     /*
      * On Windows, the data file directory is the installation
-     * directory; the python dissectors are stored under it.
+     * directory; the plugins are stored under it.
      *
      * Assume we're running the installed version of Wireshark;
      * on Windows, the data file directory is the directory
      * in which the Wireshark binary resides.
      */
-    wspython_dir = g_strdup_printf("%s\\python\\%s", get_datafile_dir(),
-                                   VERSION);
+    plugin_dir = g_build_filename(get_datafile_dir(), "plugins", VERSION, (gchar *)NULL);
 
     /*
      * Make sure that pathname refers to a directory.
      */
-    if (test_for_directory(wspython_dir) != EISDIR) {
+    if (test_for_directory(plugin_dir) != EISDIR) {
         /*
          * Either it doesn't refer to a directory or it
          * refers to something that doesn't exist.
          *
          * Assume that means we're running a version of
          * Wireshark we've built in a build directory,
-         * in which case {datafile dir}\python is the
+         * in which case {datafile dir}\plugins is the
          * top-level plugins source directory, and use
          * that directory and set the "we're running in
          * a build directory" flag, so the plugin
          * scanner will check all subdirectories of that
-         * directory for python dissectors.
+         * directory for plugins.
          */
-        g_free( (gpointer) wspython_dir);
-        wspython_dir = g_strdup_printf("%s\\python", get_datafile_dir());
+        g_free(plugin_dir);
+        plugin_dir = g_build_filename(get_datafile_dir(), "plugins", (gchar *)NULL);
         running_in_build_directory_flag = TRUE;
     }
 #else
@@ -1015,22 +1001,22 @@ init_wspython_dir(void)
         /*
          * We're (probably) being run from the build directory and
          * weren't started with special privileges, so we'll use
-         * the "python" subdirectory of the datafile directory
-         * (the datafile directory is the build directory).
+         * the "plugins" subdirectory of the directory where the program
+         * we're running is (that's the build directory).
          */
-        wspython_dir = g_strdup_printf("%s/epan/wspython/", get_datafile_dir());
+        plugin_dir = g_build_filename(get_progfile_dir(), "plugins", (gchar *)NULL);
     } else {
-        if (getenv("WIRESHARK_PYTHON_DIR") && !started_with_special_privs()) {
+        if (g_getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) {
             /*
              * The user specified a different directory for plugins
              * and we aren't running with special privileges.
              */
-            wspython_dir = g_strdup(getenv("WIRESHARK_PYTHON_DIR"));
+            plugin_dir = g_strdup(g_getenv("WIRESHARK_PLUGIN_DIR"));
         }
 #ifdef __APPLE__
         /*
          * If we're running from an app bundle and weren't started
-         * with special privileges, use the Contents/Resources/lib/wireshark/python
+         * with special privileges, use the Contents/PlugIns/wireshark
          * subdirectory of the app bundle.
          *
          * (appbundle_dir is not set to a non-null value if we're
@@ -1038,111 +1024,118 @@ init_wspython_dir(void)
          * it; we don't need to call started_with_special_privs().)
          */
         else if (appbundle_dir != NULL) {
-            wspython_dir = g_strdup_printf("%s/Contents/Resources/lib/wireshark/python",
-                                           appbundle_dir);
+            plugin_dir = g_build_filename(appbundle_dir, "Contents/PlugIns/wireshark", (gchar *)NULL);
         }
 #endif
         else {
-            wspython_dir = PYTHON_DIR;
+            plugin_dir = g_strdup(PLUGIN_DIR);
         }
     }
 #endif
 }
-#endif /* HAVE_PYTHON */
+
+static void
+init_plugin_pers_dir(void)
+{
+#ifdef _WIN32
+    plugin_pers_dir = get_persconffile_path(PLUGINS_DIR_NAME, FALSE);
+#else
+    plugin_pers_dir = g_build_filename(g_get_home_dir(), ".local/lib/wireshark/" PLUGINS_DIR_NAME, (gchar *)NULL);
+#endif
+}
+
+#endif /* HAVE_PLUGINS || HAVE_LUA */
 
 /*
- * Get the directory in which the python dissectors are stored.
+ * Get the directory in which the plugins are stored.
  */
 const char *
-get_wspython_dir(void)
+get_plugins_dir(void)
 {
-#ifdef HAVE_PYTHON
-    if (!wspython_dir) init_wspython_dir();
-    return wspython_dir;
+#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
+    if (!plugin_dir) init_plugin_dir();
+    return plugin_dir;
 #else
     return NULL;
 #endif
 }
 
-
+/* Get the personal plugin dir */
+const char *
+get_plugins_pers_dir(void)
+{
 #if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
+    if (!plugin_pers_dir)
+        init_plugin_pers_dir();
+    return plugin_pers_dir;
+#else
+    return NULL;
+#endif
+}
+
+#if defined(HAVE_EXTCAP)
 /*
- * Find the directory where the plugins are stored.
+ * Find the directory where the extcap hooks are stored.
  *
- * On Windows, we use the "plugin" subdirectory of the datafile directory.
+ * On Windows, we use the "extcap" subdirectory of the datafile directory.
  *
- * On UN*X, we use the PLUGIN_DIR value supplied by the configure
+ * On UN*X, we use the EXTCAP_DIR value supplied by the configure
  * script, unless we think we're being run from the build directory,
- * in which case we use the "plugin" subdirectory of the datafile directory.
+ * in which case we use the "extcap" subdirectory of the datafile directory.
  *
  * In both cases, we then use the subdirectory of that directory whose
  * name is the version number.
  *
  * XXX - if we think we're being run from the build directory, perhaps we
- * should have the plugin code not look in the version subdirectory
- * of the plugin directory, but look in all of the subdirectories
- * of the plugin directory, so it can just fetch the plugins built
+ * should have the extcap code not look in the version subdirectory
+ * of the extcap directory, but look in all of the subdirectories
+ * of the extcap directory, so it can just fetch the extcap hooks built
  * as part of the build process.
  */
-static const char *plugin_dir = NULL;
+static char *extcap_dir = NULL;
 
-static void
-init_plugin_dir(void)
-{
+static void init_extcap_dir(void) {
 #ifdef _WIN32
+    const char *alt_extcap_path;
+
     /*
      * On Windows, the data file directory is the installation
-     * directory; the plugins are stored under it.
+     * directory; the extcap hooks are stored under it.
      *
      * Assume we're running the installed version of Wireshark;
      * on Windows, the data file directory is the directory
      * in which the Wireshark binary resides.
      */
-    plugin_dir = g_strdup_printf("%s\\plugins\\%s", get_datafile_dir(),
-                     VERSION);
-
-    /*
-     * Make sure that pathname refers to a directory.
-     */
-    if (test_for_directory(plugin_dir) != EISDIR) {
+    alt_extcap_path = g_getenv("WIRESHARK_EXTCAP_DIR");
+    if (alt_extcap_path) {
         /*
-         * Either it doesn't refer to a directory or it
-         * refers to something that doesn't exist.
-         *
-         * Assume that means we're running a version of
-         * Wireshark we've built in a build directory,
-         * in which case {datafile dir}\plugins is the
-         * top-level plugins source directory, and use
-         * that directory and set the "we're running in
-         * a build directory" flag, so the plugin
-         * scanner will check all subdirectories of that
-         * directory for plugins.
+         * The user specified a different directory for extcap hooks.
          */
-        g_free( (gpointer) plugin_dir);
-        plugin_dir = g_strdup_printf("%s\\plugins", get_datafile_dir());
-        running_in_build_directory_flag = TRUE;
+        extcap_dir = g_strdup(alt_extcap_path);
+    } else {
+        extcap_dir = g_build_filename(get_datafile_dir(), "extcap", (gchar *)NULL);
     }
 #else
     if (running_in_build_directory_flag) {
         /*
          * We're (probably) being run from the build directory and
          * weren't started with special privileges, so we'll use
-         * the "plugins" subdirectory of the directory where the program
+         * the "extcap hooks" subdirectory of the directory where the program
          * we're running is (that's the build directory).
          */
-        plugin_dir = g_strdup_printf("%s/plugins", get_progfile_dir());
+        extcap_dir = g_build_filename(get_progfile_dir(), "extcap", (gchar *)NULL);
     } else {
-        if (getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) {
+        if (g_getenv("WIRESHARK_EXTCAP_DIR") && !started_with_special_privs()) {
             /*
-             * The user specified a different directory for plugins
+             * The user specified a different directory for extcap hooks
              * and we aren't running with special privileges.
              */
-            plugin_dir = g_strdup(getenv("WIRESHARK_PLUGIN_DIR"));
+            extcap_dir = g_strdup(g_getenv("WIRESHARK_EXTCAP_DIR"));
         }
 #ifdef __APPLE__
         /*
          * If we're running from an app bundle and weren't started
-         * with special privileges, use the Contents/Resources/lib/wireshark/plugins
+         * with special privileges, use the Contents/MacOS/extcap
          * subdirectory of the app bundle.
          *
          * (appbundle_dir is not set to a non-null value if we're
@@ -1150,27 +1143,28 @@ init_plugin_dir(void)
          * it; we don't need to call started_with_special_privs().)
          */
         else if (appbundle_dir != NULL) {
-            plugin_dir = g_strdup_printf("%s/Contents/Resources/lib/wireshark/plugins",
-                                         appbundle_dir);
+            extcap_dir = g_build_filename(appbundle_dir, "Contents/MacOS/extcap", (gchar *)NULL);
         }
 #endif
         else {
-            plugin_dir = PLUGIN_DIR;
+            extcap_dir = g_strdup(EXTCAP_DIR);
         }
     }
 #endif
 }
-#endif /* HAVE_PLUGINS || HAVE_LUA */
+#endif /* HAVE_EXTCAP */
 
 /*
- * Get the directory in which the plugins are stored.
+ * Get the directory in which the extcap hooks are stored.
+ *
+ * XXX - A fix instead of HAVE_EXTCAP must be found
  */
 const char *
-get_plugin_dir(void)
-{
-#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
-    if (!plugin_dir) init_plugin_dir();
-    return plugin_dir;
+get_extcap_dir(void) {
+#if defined(HAVE_EXTCAP)
+    if (!extcap_dir)
+        init_extcap_dir();
+    return extcap_dir;
 #else
     return NULL;
 #endif
@@ -1202,20 +1196,6 @@ get_systemfile_dir(void)
 #endif
 }
 
-/*
- * Name of directory, under the user's home directory, in which
- * personal configuration files are stored.
- */
-#ifdef _WIN32
-#define PF_DIR "Wireshark"
-#else
-/*
- * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
- * it ".wireshark" for now.
- */
-#define PF_DIR ".wireshark"
-#endif
-
 void
 set_profile_name(const gchar *profilename)
 {
@@ -1251,7 +1231,7 @@ has_global_profiles(void)
 {
     WS_DIR *dir;
     WS_DIRENT *file;
-    const gchar *global_dir = get_global_profiles_dir();
+    gchar *global_dir = get_global_profiles_dir();
     gchar *filename;
     gboolean has_global = FALSE;
 
@@ -1270,7 +1250,7 @@ has_global_profiles(void)
         }
         ws_dir_close(dir);
     }
-
+    g_free(global_dir);
     return has_global;
 }
 
@@ -1284,22 +1264,33 @@ profile_store_persconffiles(gboolean store)
 }
 
 /*
- * Get the directory in which personal configuration files reside;
- * in UNIX-compatible systems, it's ".wireshark", under the user's home
- * directory, and on Windows systems, it's "Wireshark", under %APPDATA%
- * or, if %APPDATA% isn't set, it's "%USERPROFILE%\Application Data"
- * (which is what %APPDATA% normally is on Windows 2000).
+ * Get the directory in which personal configuration files reside.
+ *
+ * On Windows, it's "Wireshark", under %APPDATA% or, if %APPDATA% isn't set,
+ * it's "%USERPROFILE%\Application Data" (which is what %APPDATA% normally
+ * is on Windows 2000).
+ *
+ * On UNIX-compatible systems, we first look in XDG_CONFIG_HOME/wireshark
+ * and, if that doesn't exist, ~/.wireshark, for backwards compatibility.
+ * If neither exists, we use XDG_CONFIG_HOME/wireshark, so that the directory
+ * is initially created as XDG_CONFIG_HOME/wireshark.  We use that regardless
+ * of whether the user is running under an XDG desktop or not, so that
+ * if the user's home directory is on a server and shared between
+ * different desktop environments on different machines, they can all
+ * share the same configuration file directory.
+ *
+ * XXX - what about stuff that shouldn't be shared between machines,
+ * such as plugins in the form of shared loadable images?
  */
 static const char *
 get_persconffile_dir_no_profile(void)
 {
 #ifdef _WIN32
-    char *appdatadir;
-    char *userprofiledir;
-    char *altappdatapath;
+    const char *env;
 #else
-    const char *homedir;
+    char *xdg_path, *path;
     struct passwd *pwd;
+    const char *homedir;
 #endif
 
     /* Return the cached value, if available */
@@ -1310,62 +1301,67 @@ get_persconffile_dir_no_profile(void)
     /*
      * See if the user has selected an alternate environment.
      */
-    altappdatapath = getenv_utf8("WIRESHARK_APPDATA");
-    if (altappdatapath != NULL) {
-        persconffile_dir = altappdatapath;
+    env = g_getenv("WIRESHARK_APPDATA");
+    if (env != NULL) {
+        persconffile_dir = g_strdup(env);
         return persconffile_dir;
     }
 
     /*
-     * See if we are running in a U3 environment.
+     * Use %APPDATA% or %USERPROFILE%, so that configuration
+     * files are stored in the user profile, rather than in
+     * the home directory.  The Windows convention is to store
+     * configuration information in the user profile, and doing
+     * so means you can use Wireshark even if the home directory
+     * is an inaccessible network drive.
      */
-    altappdatapath = getenv_utf8("U3_APP_DATA_PATH");
-    if (altappdatapath != NULL) {
+    env = g_getenv("APPDATA");
+    if (env != NULL) {
         /*
-         * We are; use the U3 application data path.
+         * Concatenate %APPDATA% with "\Wireshark".
          */
-        persconffile_dir = altappdatapath;
-    } else {
-        /*
-         * Use %APPDATA% or %USERPROFILE%, so that configuration
-         * files are stored in the user profile, rather than in
-         * the home directory.  The Windows convention is to store
-         * configuration information in the user profile, and doing
-         * so means you can use Wireshark even if the home directory
-         * is an inaccessible network drive.
-         */
-        appdatadir = getenv_utf8("APPDATA");
-        if (appdatadir != NULL) {
-            /*
-             * Concatenate %APPDATA% with "\Wireshark".
-             */
-            persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-                               appdatadir, PF_DIR);
-        } else {
-            /*
-             * OK, %APPDATA% wasn't set, so use
-             * %USERPROFILE%\Application Data.
-             */
-            userprofiledir = getenv_utf8("USERPROFILE");
-            if (userprofiledir != NULL) {
-                persconffile_dir = g_strdup_printf(
-                    "%s" G_DIR_SEPARATOR_S "Application Data" G_DIR_SEPARATOR_S "%s",
-                    userprofiledir, PF_DIR);
-            } else {
-                /*
-                 * Give up and use "C:".
-                 */
-                persconffile_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
-            }
-        }
+        persconffile_dir = g_build_filename(env, "Wireshark", NULL);
+        return persconffile_dir;
+    }
+
+    /*
+     * OK, %APPDATA% wasn't set, so use %USERPROFILE%\Application Data.
+     */
+    env = g_getenv("USERPROFILE");
+    if (env != NULL) {
+        persconffile_dir = g_build_filename(env, "Application Data", "Wireshark", NULL);
+        return persconffile_dir;
     }
+
+    /*
+     * Give up and use "C:".
+     */
+    persconffile_dir = g_build_filename("C:", "Wireshark", NULL);
+    return persconffile_dir;
 #else
     /*
-     * If $HOME is set, use that.
+     * Check if XDG_CONFIG_HOME/wireshark exists and is a directory.
      */
-    homedir = getenv("HOME");
+    xdg_path = g_build_filename(g_get_user_config_dir(), "wireshark", NULL);
+    if (g_file_test(xdg_path, G_FILE_TEST_IS_DIR)) {
+        persconffile_dir = xdg_path;
+        return persconffile_dir;
+    }
+
+    /*
+     * It doesn't exist, or it does but isn't a directory, so try
+     * ~/.wireshark.
+     *
+     * If $HOME is set, use that for ~.
+     *
+     * (Note: before GLib 2.36, g_get_home_dir() didn't look at $HOME,
+     * but we always want to do so, so we don't use g_get_home_dir().)
+     */
+    homedir = g_getenv("HOME");
     if (homedir == NULL) {
         /*
+         * It's not set.
+         *
          * Get their home directory from the password file.
          * If we can't even find a password file entry for them,
          * use "/tmp".
@@ -1377,10 +1373,21 @@ get_persconffile_dir_no_profile(void)
             homedir = "/tmp";
         }
     }
-    persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
-#endif
+    path = g_build_filename(homedir, ".wireshark", NULL);
+    if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
+        g_free(xdg_path);
+        persconffile_dir = path;
+        return persconffile_dir;
+    }
 
+    /*
+     * Neither are directories that exist; use the XDG path, so we'll
+     * create that as necessary.
+     */
+    g_free(path);
+    persconffile_dir = xdg_path;
     return persconffile_dir;
+#endif
 }
 
 void
@@ -1390,42 +1397,70 @@ set_persconffile_dir(const char *p)
     persconffile_dir = g_strdup(p);
 }
 
-const char *
+char *
 get_profiles_dir(void)
 {
-    static char *profiles_dir = NULL;
-
-    g_free (profiles_dir);
-    profiles_dir = g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
+    return g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
                     G_DIR_SEPARATOR_S, PROFILES_DIR);
-
-    return profiles_dir;
 }
 
-const char *
-get_global_profiles_dir(void)
+int
+create_profiles_dir(char **pf_dir_path_return)
 {
-    static char *global_profiles_dir = NULL;
+    char *pf_dir_path;
+    ws_statb64 s_buf;
 
-    if (!global_profiles_dir) {
-        global_profiles_dir = g_strdup_printf ("%s%s%s", get_datafile_dir(),
-                               G_DIR_SEPARATOR_S, PROFILES_DIR);
+    /*
+     * Create the "Default" personal configuration files directory, if necessary.
+     */
+    if (create_persconffile_profile (NULL, pf_dir_path_return) == -1) {
+        return -1;
     }
 
-    return global_profiles_dir;
+    /*
+     * Check if profiles directory exists.
+     * If not then create it.
+     */
+    pf_dir_path = get_profiles_dir ();
+    if (ws_stat64(pf_dir_path, &s_buf) != 0) {
+        if (errno != ENOENT) {
+            /* Some other problem; give up now. */
+            *pf_dir_path_return = pf_dir_path;
+            return -1;
+        }
+
+        /*
+         * It doesn't exist; try to create it.
+         */
+        int ret = ws_mkdir(pf_dir_path, 0755);
+        if (ret == -1) {
+            *pf_dir_path_return = pf_dir_path;
+            return ret;
+        }
+    }
+    g_free(pf_dir_path);
+
+    return 0;
 }
 
-static const char *
-get_persconffile_dir(const gchar *profilename)
+char *
+get_global_profiles_dir(void)
 {
-    static char *persconffile_profile_dir = NULL;
+    return g_strdup_printf ("%s%s%s", get_datafile_dir(),
+                               G_DIR_SEPARATOR_S, PROFILES_DIR);
+}
 
-    g_free (persconffile_profile_dir);
+static char *
+get_persconffile_dir(const gchar *profilename)
+{
+    char *persconffile_profile_dir = NULL, *profile_dir;
 
     if (profilename && strlen(profilename) > 0 &&
         strcmp(profilename, DEFAULT_PROFILE) != 0) {
-      persconffile_profile_dir = g_strdup_printf ("%s%s%s", get_profiles_dir (),
+      profile_dir = get_profiles_dir();
+      persconffile_profile_dir = g_strdup_printf ("%s%s%s", profile_dir,
                               G_DIR_SEPARATOR_S, profilename);
+      g_free(profile_dir);
     } else {
       persconffile_profile_dir = g_strdup (get_persconffile_dir_no_profile ());
     }
@@ -1436,20 +1471,25 @@ get_persconffile_dir(const gchar *profilename)
 gboolean
 profile_exists(const gchar *profilename, gboolean global)
 {
+    gchar *path = NULL, *global_path;
     if (global) {
-        gchar *path = g_strdup_printf ("%s%s%s", get_global_profiles_dir(),
+        global_path = get_global_profiles_dir();
+        path = g_strdup_printf ("%s%s%s", global_path,
                            G_DIR_SEPARATOR_S, profilename);
+        g_free(global_path);
         if (test_for_directory (path) == EISDIR) {
             g_free (path);
             return TRUE;
         }
-        g_free (path);
     } else {
-        if (test_for_directory (get_persconffile_dir (profilename)) == EISDIR) {
+        path = get_persconffile_dir (profilename);
+        if (test_for_directory (path) == EISDIR) {
+            g_free (path);
             return TRUE;
         }
     }
 
+    g_free (path);
     return FALSE;
 }
 
@@ -1490,16 +1530,53 @@ delete_directory (const char *directory, char **pf_dir_path_return)
     return ret;
 }
 
+static int
+reset_default_profile(char **pf_dir_path_return)
+{
+    char *profile_dir = get_persconffile_dir(NULL);
+    gchar *filename, *del_file;
+    GList *files, *file;
+    int ret = 0;
+
+    files = g_hash_table_get_keys(profile_files);
+    file = g_list_first(files);
+    while (file) {
+        filename = (gchar *)file->data;
+        del_file = g_strdup_printf("%s%s%s", profile_dir, G_DIR_SEPARATOR_S, filename);
+
+        if (file_exists(del_file)) {
+            ret = ws_remove(del_file);
+            if (ret != 0) {
+                *pf_dir_path_return = profile_dir;
+                g_free(del_file);
+                return ret;
+            }
+        }
+
+        g_free(del_file);
+        file = g_list_next(file);
+    }
+    g_list_free(files);
+
+    g_free(profile_dir);
+    return 0;
+}
+
 int
 delete_persconffile_profile(const char *profilename, char **pf_dir_path_return)
 {
-    const char *profile_dir = get_persconffile_dir(profilename);
+    if (strcmp(profilename, DEFAULT_PROFILE) == 0) {
+        return reset_default_profile(pf_dir_path_return);
+    }
+
+    char *profile_dir = get_persconffile_dir(profilename);
     int ret = 0;
 
     if (test_for_directory (profile_dir) == EISDIR) {
         ret = delete_directory (profile_dir, pf_dir_path_return);
     }
 
+    g_free(profile_dir);
     return ret;
 }
 
@@ -1507,20 +1584,21 @@ int
 rename_persconffile_profile(const char *fromname, const char *toname,
                 char **pf_from_dir_path_return, char **pf_to_dir_path_return)
 {
-    char *from_dir = g_strdup (get_persconffile_dir(fromname));
-    char *to_dir = g_strdup (get_persconffile_dir(toname));
+    char *from_dir = get_persconffile_dir(fromname);
+    char *to_dir = get_persconffile_dir(toname);
     int ret = 0;
 
     ret = ws_rename (from_dir, to_dir);
     if (ret != 0) {
-        *pf_from_dir_path_return = g_strdup (from_dir);
-        *pf_to_dir_path_return = g_strdup (to_dir);
+        *pf_from_dir_path_return = from_dir;
+        *pf_to_dir_path_return = to_dir;
+        return ret;
     }
 
     g_free (from_dir);
     g_free (to_dir);
 
-    return ret;
+    return 0;
 }
 
 /*
@@ -1533,38 +1611,31 @@ rename_persconffile_profile(const char *fromname, const char *toname,
 int
 create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
 {
-    const char *pf_dir_path;
+    char *pf_dir_path;
 #ifdef _WIN32
     char *pf_dir_path_copy, *pf_dir_parent_path;
     size_t pf_dir_parent_path_len;
+    int save_errno;
 #endif
     ws_statb64 s_buf;
     int ret;
 
     if (profilename) {
         /*
-         * Create the "Default" personal configuration files directory, if necessary.
+         * Create the personal profiles directory, if necessary.
          */
-        if (create_persconffile_profile (NULL, pf_dir_path_return) == -1) {
+        if (create_profiles_dir(pf_dir_path_return) == -1) {
             return -1;
         }
-
-        /*
-         * Check if profiles directory exists.
-         * If not then create it.
-         */
-        pf_dir_path = get_profiles_dir ();
-        if (ws_stat64(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
-            ret = ws_mkdir(pf_dir_path, 0755);
-            if (ret == -1) {
-                *pf_dir_path_return = g_strdup(pf_dir_path);
-                return ret;
-            }
-        }
     }
 
     pf_dir_path = get_persconffile_dir(profilename);
-    if (ws_stat64(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
+    if (ws_stat64(pf_dir_path, &s_buf) != 0) {
+        if (errno != ENOENT) {
+            /* Some other problem; give up now. */
+            *pf_dir_path_return = pf_dir_path;
+            return -1;
+        }
 #ifdef _WIN32
         /*
          * Does the parent directory of that directory
@@ -1583,19 +1654,33 @@ create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
         if (pf_dir_parent_path_len > 0
             && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
             && ws_stat64(pf_dir_parent_path, &s_buf) != 0) {
+            /*
+             * Not a drive letter and the stat() failed.
+             */
+            if (errno != ENOENT) {
+                /* Some other problem; give up now. */
+                *pf_dir_path_return = pf_dir_path;
+                save_errno = errno;
+                g_free(pf_dir_path_copy);
+                errno = save_errno;
+                return -1;
+            }
             /*
              * No, it doesn't exist - make it first.
              */
             ret = ws_mkdir(pf_dir_parent_path, 0755);
             if (ret == -1) {
                 *pf_dir_path_return = pf_dir_parent_path;
+                save_errno = errno;
+                g_free(pf_dir_path);
+                errno = save_errno;
                 return -1;
             }
         }
         g_free(pf_dir_path_copy);
         ret = ws_mkdir(pf_dir_path, 0755);
 #else
-        ret = ws_mkdir(pf_dir_path, 0755);
+        ret = g_mkdir_with_parents(pf_dir_path, 0755);
 #endif
     } else {
         /*
@@ -1607,14 +1692,17 @@ create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
         ret = 0;
     }
     if (ret == -1)
-        *pf_dir_path_return = g_strdup(pf_dir_path);
+        *pf_dir_path_return = pf_dir_path;
+    else
+        g_free(pf_dir_path);
+
     return ret;
 }
 
 int
 create_persconffile_dir(char **pf_dir_path_return)
 {
-  return create_persconffile_profile(persconfprofile, pf_dir_path_return);
+    return create_persconffile_profile(persconfprofile, pf_dir_path_return);
 }
 
 int
@@ -1622,18 +1710,20 @@ copy_persconffile_profile(const char *toname, const char *fromname, gboolean fro
               char **pf_filename_return, char **pf_to_dir_path_return, char **pf_from_dir_path_return)
 {
     gchar *from_dir;
-    gchar *to_dir = g_strdup (get_persconffile_dir(toname));
-    gchar *filename, *from_file, *to_file;
+    gchar *to_dir = get_persconffile_dir(toname);
+    gchar *filename, *from_file, *to_file, *global_path;
     GList *files, *file;
 
     if (from_global) {
         if (strcmp(fromname, DEFAULT_PROFILE) == 0) {
-            from_dir = g_strdup (get_global_profiles_dir());
+            from_dir = get_global_profiles_dir();
         } else {
-            from_dir = g_strdup_printf ("%s%s%s", get_global_profiles_dir(), G_DIR_SEPARATOR_S, fromname);
+            global_path = get_global_profiles_dir();
+            from_dir = g_strdup_printf ("%s%s%s", global_path, G_DIR_SEPARATOR_S, fromname);
+            g_free(global_path);
         }
     } else {
-        from_dir = g_strdup (get_persconffile_dir(fromname));
+        from_dir = get_persconffile_dir(fromname);
     }
 
     files = g_hash_table_get_keys(profile_files);
@@ -1668,9 +1758,7 @@ copy_persconffile_profile(const char *toname, const char *fromname, gboolean fro
 /*
  * Get the (default) directory in which personal data is stored.
  *
- * On Win32, this is the "My Documents" folder in the personal profile,
- * except that, if we're running from a U3 device, this is the
- * "$U3_DEVICE_DOCUMENT_PATH\My Captures" folder.
+ * On Win32, this is the "My Documents" folder in the personal profile.
  * On UNIX this is simply the current directory.
  */
 /* XXX - should this and the get_home_dir() be merged? */
@@ -1678,7 +1766,6 @@ extern const char *
 get_persdatafile_dir(void)
 {
 #ifdef _WIN32
-    char *u3devicedocumentpath;
     TCHAR tszPath[MAX_PATH];
 
     /* Return the cached value, if available */
@@ -1686,27 +1773,14 @@ get_persdatafile_dir(void)
         return persdatafile_dir;
 
     /*
-     * See if we are running in a U3 environment.
+     * Hint: SHGetFolderPath is not available on MSVC 6 - without
+     * Platform SDK
      */
-    u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
-
-    if (u3devicedocumentpath != NULL) {
-        /* the "My Captures" sub-directory is created (if it doesn't
-           exist) by u3util.exe when the U3 Wireshark is first run */
-
-        persdatafile_dir = g_strdup_printf("%s%s", u3devicedocumentpath, U3_MY_CAPTURES);
+    if (SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE)) {
+        persdatafile_dir = g_utf16_to_utf8(tszPath, -1, NULL, NULL, NULL);
         return persdatafile_dir;
     } else {
-        /*
-         * Hint: SHGetFolderPath is not available on MSVC 6 - without
-         * Platform SDK
-         */
-        if (SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE)) {
-            persdatafile_dir = g_utf16_to_utf8(tszPath, -1, NULL, NULL, NULL);
-            return persdatafile_dir;
-        } else {
-            return "";
-        }
+        return "";
     }
 #else
     return "";
@@ -1728,7 +1802,7 @@ static const char *
 get_home_dir(void)
 {
     static const char *home = NULL;
-    char *homedrive, *homepath;
+    const char *homedrive, *homepath;
     char *homestring;
     char *lastsep;
 
@@ -1741,9 +1815,9 @@ get_home_dir(void)
      * Is there a chance that it might be set but one or more of
      * HOMEDRIVE or HOMEPATH isn't set?
      */
-    homedrive = getenv_utf8("HOMEDRIVE");
+    homedrive = g_getenv("HOMEDRIVE");
     if (homedrive != NULL) {
-        homepath = getenv_utf8("HOMEPATH");
+        homepath = g_getenv("HOMEPATH");
         if (homepath != NULL) {
             /*
              * This is cached, so we don't need to worry about
@@ -1792,20 +1866,21 @@ get_home_dir(void)
 char *
 get_persconffile_path(const char *filename, gboolean from_profile)
 {
-    char *path;
+    char *path, *dir = NULL;
+
     if (do_store_persconffiles && from_profile && !g_hash_table_lookup (profile_files, filename)) {
         /* Store filenames so we know which filenames belongs to a configuration profile */
         g_hash_table_insert (profile_files, g_strdup(filename), g_strdup(filename));
     }
 
     if (from_profile) {
-      path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-                 get_persconffile_dir(persconfprofile), filename);
+        dir = get_persconffile_dir(persconfprofile);
     } else {
-      path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-                 get_persconffile_dir(NULL), filename);
+        dir = get_persconffile_dir(NULL);
     }
+    path = g_build_filename(dir, filename, NULL);
 
+    g_free(dir);
     return path;
 }
 
@@ -1819,10 +1894,13 @@ get_persconffile_path(const char *filename, gboolean from_profile)
 char *
 get_datafile_path(const char *filename)
 {
-    if (running_in_build_directory_flag && !strcmp(filename, "AUTHORS-SHORT")) {
+    if (running_in_build_directory_flag &&
+        (!strcmp(filename, "AUTHORS-SHORT") ||
+         !strcmp(filename, "hosts"))) {
         /* We're running in the build directory and the requested file is a
-         * generated file.  Return the file name in the build directory (not
-         * in the source/data directory).
+         * generated (or a test) file.  Return the file name in the build
+         * directory (not in the source/data directory).
+         * (Oh the things we do to keep the source directory pristine...)
          */
         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_progfile_dir(), filename);
     } else {
@@ -1830,14 +1908,6 @@ get_datafile_path(const char *filename)
     }
 }
 
-/* Get the personal plugin dir */
-/* Return value is malloced so the caller should g_free() it. */
-char *
-get_plugins_pers_dir(void)
-{
-    return get_persconffile_path(PLUGINS_DIR_NAME, FALSE);
-}
-
 /*
  * Return an error message for UNIX-style errno indications on open or
  * create operations.
@@ -1882,6 +1952,13 @@ file_open_error_message(int err, gboolean for_writing)
         errmsg = "The file \"%s\" could not be created because an invalid filename was specified.";
         break;
 
+#ifdef ENAMETOOLONG
+    case ENAMETOOLONG:
+        /* XXX Make sure we truncate on a character boundary. */
+        errmsg = "The file name \"%.80s" UTF8_HORIZONTAL_ELLIPSIS "\" is too long.";
+        break;
+#endif
+
     case ENOMEM:
         /*
          * The problem probably has nothing to do with how much RAM the
@@ -1913,7 +1990,7 @@ file_open_error_message(int err, gboolean for_writing)
          * Either you have a fixed swap partition or a fixed swap file,
          * and it needs to be made bigger.
          *
-         * This is UN*X, but it's not OS X, so we assume the user is
+         * This is UN*X, but it's not macOS, so we assume the user is
          * *somewhat* nerdy.
          */
 #define ENOMEM_REASON "your system is out of swap space"
@@ -1978,7 +2055,8 @@ file_exists(const char *fname)
         return FALSE;
     }
 
-#ifdef _WIN32
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
     /*
      * This is a bit tricky on win32. The st_ino field is documented as:
      * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
@@ -2129,6 +2207,52 @@ done:
     return FALSE;
 }
 
+gchar *
+data_file_url(const gchar *filename)
+{
+    gchar *file_path;
+    gchar *uri;
+
+    /* Absolute path? */
+    if(g_path_is_absolute(filename)) {
+        file_path = g_strdup(filename);
+    } else if(running_in_build_directory()) {
+        file_path = g_strdup_printf("%s/doc/%s", get_datafile_dir(), filename);
+    } else {
+        file_path = g_strdup_printf("%s/%s", get_datafile_dir(), filename);
+    }
+
+    /* XXX - check, if the file is really existing, otherwise display a simple_dialog about the problem */
+
+    /* convert filename to uri */
+    uri = g_filename_to_uri(file_path, NULL, NULL);
+    g_free(file_path);
+    return uri;
+}
+
+void
+free_progdirs(void)
+{
+    g_free(persconffile_dir);
+    persconffile_dir = NULL;
+    g_free(persdatafile_dir);
+    persdatafile_dir = NULL;
+    g_free(persconfprofile);
+    persconfprofile = NULL;
+    g_free(progfile_dir);
+    progfile_dir = NULL;
+#if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
+    g_free(plugin_dir);
+    plugin_dir = NULL;
+    g_free(plugin_pers_dir);
+    plugin_pers_dir = NULL;
+#endif
+#ifdef HAVE_EXTCAP
+    g_free(extcap_dir);
+    extcap_dir = NULL;
+#endif
+}
+
 /*
  * Editor modelines
  *