U3 packaging, utility and Wireshark modifications that allows Wireshark to be run...
[obnox/wireshark/wip.git] / epan / filesystem.c
index 69bc56ffffdec03c90e696fcecf12c40c0f28d1f..068042896abeccca3dcdd3a82b50e45a9f5881d3 100644 (file)
@@ -3,8 +3,8 @@
  *
  * $Id$
  *
- * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@ethereal.com>
+ * Wireshark - Network traffic analyzer
+ * By Gerald Combs <gerald@wireshark.org>
  * Copyright 1998 Gerald Combs
  *
  * This program is free software; you can redistribute it and/or
 #include <sys/stat.h>
 #endif
 
-#ifdef HAVE_WINDOWS_H
+#ifdef _WIN32
 #include <windows.h>
-#endif
-
-#ifdef HAVE_DIRECT_H
-#include <direct.h>            /* to declare "mkdir()" on Windows */
-#endif
-
-#ifndef _WIN32
+#include <tchar.h>
+#include "epan/strutil.h"
+#else
 #include <pwd.h>
 #endif
 
 #include "filesystem.h"
+#include <wiretap/file_util.h>
 
 /*
  * Given a pathname, return a pointer to the last pathname separator
@@ -184,7 +181,7 @@ test_for_directory(const char *path)
 {
        struct stat statb;
 
-       if (stat(path, &statb) < 0)
+       if (eth_stat(path, &statb) < 0)
                return errno;
 
        if (S_ISDIR(statb.st_mode))
@@ -198,7 +195,7 @@ test_for_fifo(const char *path)
 {
        struct stat statb;
 
-       if (stat(path, &statb) < 0)
+       if (eth_stat(path, &statb) < 0)
                return errno;
 
        if (S_ISFIFO(statb.st_mode))
@@ -207,12 +204,282 @@ test_for_fifo(const char *path)
                return 0;
 }
 
+static char *progfile_dir;
+
+/*
+ * Get the pathname of the directory from which the executable came,
+ * and save it for future use.  Returns NULL on success, and a
+ * g_mallocated string containing an error on failure.
+ */
+char *
+init_progfile_dir(const char *arg0
+#ifdef _WIN32
+       _U_
+#endif
+)
+{
+       char *dir_end;
+       char *path;
+#ifdef _WIN32
+       TCHAR prog_pathname_w[_MAX_PATH+2];
+       size_t progfile_dir_len;
+        char *prog_pathname;
+        DWORD error;
+        TCHAR *msg_w;
+        guchar *msg;
+        size_t msglen;
+
+       /*
+        * Attempt to get the full pathname of the currently running
+        * program.
+        */
+       if (GetModuleFileName(NULL, prog_pathname_w, sizeof prog_pathname_w) != 0) {
+                /*
+                 * XXX - Should we use g_utf16_to_utf8(), as in
+                 * getenv_utf8()?
+                 */
+                prog_pathname = utf_16to8(prog_pathname_w);
+               /*
+                * We got it; strip off the last component, which would be
+                * the file name of the executable, giving us the pathname
+                * of the directory where the executable resies
+                *
+                * First, find the last "\" in the directory, as that
+                * marks the end of the directory pathname.
+                *
+                * XXX - Can the pathname be something such as
+                * "C:wireshark.exe"?  Or is it always a full pathname
+                * beginning with "\" after the drive letter?
+                */
+               dir_end = strrchr(prog_pathname, '\\');
+               if (dir_end != NULL) {
+                       /*
+                        * Found it - now figure out how long the program
+                        * directory pathname will be.
+                        */
+                       progfile_dir_len = (dir_end - prog_pathname);
+
+                       /*
+                        * Allocate a buffer for the program directory
+                        * pathname, and construct it.
+                        */
+                       path = g_malloc(progfile_dir_len + 1);
+                       strncpy(path, prog_pathname, progfile_dir_len);
+                       path[progfile_dir_len] = '\0';
+                       progfile_dir = path;
+
+                       return NULL;    /* we succeeded */
+               } else {
+                       /*
+                        * OK, no \ - what do we do now?
+                        */
+                       return g_strdup_printf("No \\ in executable pathname \"%s\"",
+                           prog_pathname);
+               }
+       } else {
+               /*
+                * Oh, well.  Return an indication of the error.
+                */
+               error = GetLastError();
+               if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
+                   NULL, error, 0, (LPTSTR) &msg_w, 0, NULL) == 0) {
+                       /*
+                        * Gak.  We can't format the message.
+                        */
+                       return g_strdup_printf("GetModuleFileName failed: %u (FormatMessage failed: %u)",
+                           error, GetLastError());
+               }
+               msg = utf_16to8(msg_w);
+               LocalFree(msg_w);
+               /*
+                * "FormatMessage()" "helpfully" sticks CR/LF at the
+                * end of the message.  Get rid of it.
+                */
+               msglen = strlen(msg);
+               if (msglen >= 2) {
+                       msg[msglen - 1] = '\0';
+                       msg[msglen - 2] = '\0';
+               }
+               return g_strdup_printf("GetModuleFileName failed: %s (%u)",
+                   msg, error);
+       }
+#else
+       char *prog_pathname;
+       char *curdir;
+       long path_max;
+       char *pathstr;
+       char *path_start, *path_end;
+       size_t path_component_len;
+       char *retstr;
+
+       /*
+        * Try to figure out the directory in which the currently running
+        * program resides, given the argv[0] it was started with.  That
+        * might be the absolute path of the program, or a path relative
+        * to the current directory of the process that started it, or
+        * just a name for the program if it was started from the command
+        * line and was searched for in $PATH.  It's not guaranteed to be
+        * any of those, however, so there are no guarantees....
+        */
+       if (arg0[0] == '/') {
+               /*
+                * It's an absolute path.
+                */
+               prog_pathname = g_strdup(arg0);
+       } else if (strchr(arg0, '/') != NULL) {
+               /*
+                * It's a relative path, with a directory in it.
+                * Get the current directory, and combine it
+                * with that directory.
+                */
+               path_max = pathconf(".", _PC_PATH_MAX);
+               if (path_max == -1) {
+                       /*
+                        * We have no idea how big a buffer to
+                        * allocate for the current directory.
+                        */
+                       return g_strdup_printf("pathconf failed: %s\n",
+                           strerror(errno));
+               }
+               curdir = g_malloc(path_max);
+               if (getcwd(curdir, path_max) == NULL) {
+                       /*
+                        * It failed - give up, and just stick
+                        * with DATAFILE_DIR.
+                        */
+                       g_free(curdir);
+                       return g_strdup_printf("getcwd failed: %s\n",
+                           strerror(errno));
+               }
+               path = g_malloc(strlen(curdir) + 1 + strlen(arg0) + 1);
+               strcpy(path, curdir);
+               strcat(path, "/");
+               strcat(path, arg0);
+               g_free(curdir);
+               prog_pathname = path;
+       } else {
+               /*
+                * It's just a file name.
+                * Search the path for a file with that name
+                * that's executable.
+                */
+               prog_pathname = NULL;   /* haven't found it yet */
+               pathstr = getenv("PATH");
+               path_start = pathstr;
+               if (path_start != NULL) {
+                       while (*path_start != '\0') {
+                               path_end = strchr(path_start, ':');
+                               if (path_end == NULL)
+                                       path_end = path_start + strlen(path_start);
+                               path_component_len = path_end - path_start;
+                               path = g_malloc(path_component_len + 1
+                                   + strlen(arg0) + 1);
+                               memcpy(path, path_start, path_component_len);
+                               path[path_component_len] = '\0';
+                               strcat(path, "/");
+                               strcat(path, arg0);
+                               if (access(path, X_OK) == 0) {
+                                       /*
+                                        * Found it!
+                                        */
+                                       prog_pathname = path;
+                                       break;
+                               }
+
+                               /*
+                                * That's not it.  If there are more
+                                * path components to test, try them.
+                                */
+                               if (*path_end == '\0') {
+                                       /*
+                                        * There's nothing more to try.
+                                        */
+                                       break;
+                               }
+                               if (*path_end == ':')
+                                       path_end++;
+                               path_start = path_end;
+                               g_free(path);
+                       }
+                       if (prog_pathname == NULL) {
+                               /*
+                                * Program not found in path.
+                                */
+                               return g_strdup_printf("\"%s\" not found in \"%s\"",
+                                   arg0, pathstr);
+                       }
+               } else {
+                       /*
+                        * PATH isn't set.
+                        * XXX - should we pick a default?
+                        */
+                       return g_strdup("PATH isn't set");
+               }
+       }
+
+       /*
+        * OK, we have what we think is the pathname
+        * of the program.
+        *
+        * First, find the last "/" in the directory,
+        * as that marks the end of the directory pathname.
+        */
+       dir_end = strrchr(prog_pathname, '/');
+       if (dir_end != NULL) {
+               /*
+                * Found it.  Strip off the last component,
+                * as that's the path of the program.
+                */
+               *dir_end = '\0';
+
+               /*
+                * Is there a "/.libs" at the end?
+                */
+               dir_end = strrchr(prog_pathname, '/');
+               if (dir_end != NULL) {
+                       if (strcmp(dir_end, "/.libs") == 0) {
+                               /*
+                                * Yup, it's ".libs".
+                                * Strip that off; it's an
+                                * artifact of libtool.
+                                */
+                               *dir_end = '\0';
+                       }
+               }
+
+               /*
+                * OK, we have the path we want.
+                */
+               progfile_dir = prog_pathname;
+               return NULL;
+       } else {
+               /*
+                * This "shouldn't happen"; we apparently
+                * have no "/" in the pathname.
+                * Just free up prog_pathname.
+                */
+               retstr = g_strdup_printf("No / found in \"%s\"", prog_pathname);
+               g_free(prog_pathname);
+               return retstr;
+       }
+#endif
+}
+
 /*
- * Get the directory in which Ethereal's global configuration and data
- * files are stored.
+ * Get the directory in which the program resides.
+ */
+const char *
+get_progfile_dir(void)
+{
+       return progfile_dir;
+}
+
+/*
+ * Get the directory in which the global configuration and data files are
+ * stored.
  *
- * XXX - if we ever make libethereal a real library, used by multiple
- * applications (more than just Tethereal and versions of Ethereal with
+ * XXX - if we ever make libwireshark a real library, used by multiple
+ * applications (more than just TShark and versions of Wireshark with
  * various UIs), should the configuration files belong to the library
  * (and be shared by all those applications) or to the applications?
  *
@@ -225,93 +492,67 @@ test_for_fifo(const char *path)
  * passed in as an argument, in some call, on UNIX.
  *
  * Note that some of those configuration files might be used by code in
- * libethereal, some of them might be used by dissectors (would they
- * belong to libethereal, the application, or a separate library?),
- * and some of them might be used by other code (the Ethereal preferences
+ * libwireshark, some of them might be used by dissectors (would they
+ * belong to libwireshark, the application, or a separate library?),
+ * and some of them might be used by other code (the Wireshark preferences
  * file includes resolver preferences that control the behavior of code
- * in libethereal, dissector preferences, and UI preferences, for
+ * in libwireshark, dissector preferences, and UI preferences, for
  * example).
  */
 const char *
 get_datafile_dir(void)
 {
 #ifdef _WIN32
-       char prog_pathname[_MAX_PATH+2];
-       char *dir_end;
-       size_t datafile_dir_len;
-       static char *datafile_dir;
+       char *u3deviceexecpath;
+#endif
+       static char *datafile_dir = NULL;
 
-       /*
-        * Have we already gotten the pathname?
-        * If so, just return it.
-        */
-       if (datafile_dir != NULL)
+       if(datafile_dir != NULL)
                return datafile_dir;
 
-       /*
-        * No, we haven't.
-        * Start out by assuming it's the default installation directory.
-        */
-       datafile_dir = "C:\\Program Files\\Ethereal\\";
+#ifdef _WIN32
+
+       u3deviceexecpath = getenv_utf8("U3_DEVICE_EXEC_PATH");
+
+       if(u3deviceexecpath != NULL) {
+               datafile_dir = u3deviceexecpath;
+       } else {
 
-       /*
-        * Now we attempt to get the full pathname of the currently running
-        * program, under the assumption that 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\Ethereal\InstallDir"?
-        * If so, perhaps we should read that from the registry,
-        * instead.
-        */
-       if (GetModuleFileName(NULL, prog_pathname, sizeof prog_pathname) != 0) {
                /*
-                * If the program is an installed version, the full pathname
-                * includes the pathname of the directory in which it was
-                * installed; get that directory's pathname, and construct
-                * from it the pathname of the directory in which the
-                * plugins were installed.
+                * 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.
                 *
-                * First, find the last "\\" in the directory, as that
-                * marks the end of the directory pathname.
-                *
-                * XXX - Can the pathname be something such as
-                * "C:ethereal.exe"?  Or is it always a full pathname
-                * beginning with "\\" after the drive letter?
+                * 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.
                 */
-               dir_end = strrchr(prog_pathname, '\\');
-               if (dir_end != NULL) {
+               if (progfile_dir != NULL)
+                       datafile_dir = progfile_dir;
+               else 
                        /*
-                        * Found it - now figure out how long the datafile
-                        * directory pathname will be.
-                        */
-                       datafile_dir_len = (dir_end - prog_pathname);
-
-                       /*
-                        * Allocate a buffer for the plugin directory
-                        * pathname, and construct it.
-                        */
-                       datafile_dir = g_malloc(datafile_dir_len + 1);
-                       strncpy(datafile_dir, prog_pathname, datafile_dir_len);
-                       datafile_dir[datafile_dir_len] = '\0';
-               }
+                       * No, we don't.
+                       * Fall back on the default installation directory.
+                       */
+                       datafile_dir = "C:\\Program Files\\Wireshark\\";
        }
-       return datafile_dir;
 #else
        /*
         * Just use DATAFILE_DIR, as that's what the configure script
         * set it to be.
         */
-       return DATAFILE_DIR;
+       datafile_dir = DATAFILE_DIR;
 #endif
+       return datafile_dir;
 }
 
 /*
  * Get the directory in which files that, at least on UNIX, are
  * system files (such as "/etc/ethers") are stored; on Windows,
- * there's no "/etc" directory, so we get them from the Ethereal
- * global configuration and data file directory.
+ * there's no "/etc" directory, so we get them from the global
+ * configuration and data file directory.
  */
 const char *
 get_systemfile_dir(void)
@@ -328,19 +569,64 @@ get_systemfile_dir(void)
  * personal configuration files are stored.
  */
 #ifdef _WIN32
-#define PF_DIR "Ethereal"
+#define PF_DIR "Wireshark"
 #else
 /*
  * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
- * it ".ethereal" for now.
+ * it ".wireshark" for now.
  */
-#define PF_DIR ".ethereal"
+#define PF_DIR ".wireshark"
+#endif
+
+#ifdef WIN32
+/* utf8 version of getenv, needed to get win32 filename paths */
+char *getenv_utf8(const char *varname)
+{
+       char *envvar;
+       wchar_t *envvarw;
+       wchar_t *varnamew;
+
+       envvar = getenv(varname);
+
+       /* since GLib 2.6 we need an utf8 version of the filename */
+#if GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 6)
+       if (!G_WIN32_HAVE_WIDECHAR_API ()) {
+               /* Windows OT (9x, ME), convert from current code page to utf8 */
+               /* it's the best we can do here ... */
+        envvar = g_locale_to_utf8(envvar, -1, NULL, NULL, NULL);
+               /* XXX - memleak */
+               return envvar;
+       }
+
+       /* Windows NT, 2000, XP, ... */
+       /* using the wide char version of getenv should work under all circumstances */
+
+       /* convert given varname to utf16, needed by _wgetenv */
+       varnamew = g_utf8_to_utf16(varname, -1, NULL, NULL, NULL);
+       if (varnamew == NULL) {
+               return envvar;
+       }
+
+       /* use wide char version of getenv */
+       envvarw = _wgetenv(varnamew);
+       g_free(varnamew);
+       if (envvarw == NULL) {
+               return envvar;
+       }
+
+       /* convert value to utf8 */
+       envvar = g_utf16_to_utf8(envvarw, -1, NULL, NULL, NULL);
+       /* XXX - memleak */
+#endif
+
+       return envvar;
+}
 #endif
 
 /*
  * Get the directory in which personal configuration files reside;
- * in UNIX-compatible systems, it's ".ethereal", under the user's home
- * directory, and on Windows systems, it's "Ethereal", under %APPDATA%
+ * 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).
  */
@@ -350,8 +636,9 @@ get_persconffile_dir(void)
 #ifdef _WIN32
        char *appdatadir;
        char *userprofiledir;
+       char *u3appdatapath;
 #else
-       char *homedir;
+       const char *homedir;
        struct passwd *pwd;
 #endif
        static char *pf_dir = NULL;
@@ -361,40 +648,50 @@ get_persconffile_dir(void)
                return pf_dir;
 
 #ifdef _WIN32
+
        /*
-        * 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
-        * Ethereal even if the home directory is an inaccessible
-        * network drive.
+        * See if we are running in a U3 environment 
         */
-       appdatadir = getenv("APPDATA");
-       if (appdatadir != NULL) {
-               /*
-                * Concatenate %APPDATA% with "\Ethereal".
-                */
-               pf_dir = g_malloc(strlen(appdatadir) + strlen(PF_DIR) + 2);
-               sprintf(pf_dir, "%s" G_DIR_SEPARATOR_S "%s", appdatadir,
-                   PF_DIR);
+
+       u3appdatapath = getenv_utf8("U3_APP_DATA_PATH");        
+               
+       if(u3appdatapath != NULL) {
+
+               pf_dir = u3appdatapath;
+
        } else {
+       
                /*
-                * OK, %APPDATA% wasn't set, so use
-                * %USERPROFILE%\Application Data.
+                * 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.
                 */
-               userprofiledir = getenv("USERPROFILE");
-               if (userprofiledir != NULL) {
-                       pf_dir = g_malloc(strlen(userprofiledir) +
-                           strlen("Application Data") + strlen(PF_DIR) + 3);
-                       sprintf(pf_dir,
-                           "%s" G_DIR_SEPARATOR_S "Application Data" G_DIR_SEPARATOR_S "%s",
-                           userprofiledir, PF_DIR);
+               appdatadir = getenv_utf8("APPDATA");
+               if (appdatadir != NULL) {
+                       /*
+                        * Concatenate %APPDATA% with "\Wireshark".
+                        */
+                       pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
+                               appdatadir, PF_DIR);
                } else {
                        /*
-                        * Give up and use "C:".
+                        * OK, %APPDATA% wasn't set, so use
+                        * %USERPROFILE%\Application Data.
                         */
-                       pf_dir = g_malloc(strlen("C:") + strlen(PF_DIR) + 2);
-                       sprintf(pf_dir, "C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
+                       userprofiledir = getenv_utf8("USERPROFILE");
+                       if (userprofiledir != NULL) {
+                                       pf_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:".
+                                */
+                               pf_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
+                       }
                }
        }
 #else
@@ -418,8 +715,7 @@ get_persconffile_dir(void)
                } else
                        homedir = "/tmp";
        }
-       pf_dir = g_malloc(strlen(homedir) + strlen(PF_DIR) + 2);
-       sprintf(pf_dir, "%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
+       pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
 #endif
 
        return pf_dir;
@@ -444,7 +740,7 @@ create_persconffile_dir(char **pf_dir_path_return)
        int ret;
 
        pf_dir_path = get_persconffile_dir();
-       if (stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
+       if (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
 #ifdef _WIN32
                /*
                 * Does the parent directory of that directory
@@ -462,20 +758,20 @@ create_persconffile_dir(char **pf_dir_path_return)
                pf_dir_parent_path_len = strlen(pf_dir_parent_path);
                if (pf_dir_parent_path_len > 0
                    && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
-                   && stat(pf_dir_parent_path, &s_buf) != 0) {
+                   && eth_stat(pf_dir_parent_path, &s_buf) != 0) {
                        /*
                         * No, it doesn't exist - make it first.
                         */
-                       ret = mkdir(pf_dir_parent_path);
+                       ret = eth_mkdir(pf_dir_parent_path, 0755);
                        if (ret == -1) {
                                *pf_dir_path_return = pf_dir_parent_path;
                                return -1;
                        }
                }
                g_free(pf_dir_path_copy);
-               ret = mkdir(pf_dir_path);
+               ret = eth_mkdir(pf_dir_path, 0755);
 #else
-               ret = mkdir(pf_dir_path, 0755);
+               ret = eth_mkdir(pf_dir_path, 0755);
 #endif
        } else {
                /*
@@ -512,9 +808,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("HOMEDRIVE");
+       homedrive = getenv_utf8("HOMEDRIVE");
        if (homedrive != NULL) {
-               homepath = getenv("HOMEPATH");
+               homepath = getenv_utf8("HOMEPATH");
                if (homepath != NULL) {
                        /*
                         * This is cached, so we don't need to worry about
@@ -555,7 +851,7 @@ get_home_dir(void)
  * file name.
  *
  * On Win32, if "for_writing" is FALSE, we check whether the file exists
- * and, if not, construct a path name relative to the ".ethereal"
+ * and, if not, construct a path name relative to the ".wireshark"
  * subdirectory of the user's home directory, and check whether that
  * exists; if it does, we return that, so that configuration files
  * from earlier versions can be read.
@@ -573,24 +869,20 @@ get_persconffile_path(const char *filename, gboolean for_writing
        char *old_path;
 #endif
 
-       path = (gchar *) g_malloc(strlen(get_persconffile_dir()) +
-           strlen(filename) + 2);
-       sprintf(path, "%s" G_DIR_SEPARATOR_S "%s", get_persconffile_dir(),
+       path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_persconffile_dir(),
            filename);
 #ifdef _WIN32
        if (!for_writing) {
-               if (stat(path, &s_buf) != 0 && errno == ENOENT) {
+               if (eth_stat(path, &s_buf) != 0 && errno == ENOENT) {
                        /*
                         * OK, it's not in the personal configuration file
-                        * directory; is it in the ".ethereal" subdirectory
+                        * directory; is it in the ".wireshark" subdirectory
                         * of their home directory?
                         */
-                       old_path = (gchar *) g_malloc(strlen(get_home_dir()) +
-                           strlen(".ethereal") + strlen(filename) + 3);
-                       sprintf(old_path,
-                           "%s" G_DIR_SEPARATOR_S ".ethereal" G_DIR_SEPARATOR_S "%s",
+                       old_path = g_strdup_printf(
+                           "%s" G_DIR_SEPARATOR_S ".wireshark" G_DIR_SEPARATOR_S "%s",
                            get_home_dir(), filename);
-                       if (stat(old_path, &s_buf) == 0) {
+                       if (eth_stat(old_path, &s_buf) == 0) {
                                /*
                                 * OK, it exists; return it instead.
                                 */
@@ -611,21 +903,16 @@ get_persconffile_path(const char *filename, gboolean for_writing
 char *
 get_datafile_path(const char *filename)
 {
-       char *path;
 
-       path = (gchar *) g_malloc(strlen(get_datafile_dir()) +
-           strlen(filename) + 2);
-       sprintf(path, "%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
+       return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
            filename);
-
-       return path;
 }
 
 /* Delete a file */
 gboolean
 deletefile(const char *path)
 {
-       return unlink(path) == 0;
+       return eth_unlink(path) == 0;
 }
 
 /*
@@ -634,23 +921,18 @@ deletefile(const char *path)
  */
 char *get_tempfile_path(const char *filename)
 {
-       char *path;
 
-       path = (gchar *) g_malloc(strlen(g_get_tmp_dir()) +
-           strlen(filename) + 2);
-       sprintf(path, "%s" G_DIR_SEPARATOR_S "%s", g_get_tmp_dir(), filename);
-
-       return path;
+       return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", g_get_tmp_dir(), filename);
 }
 
 /*
  * Return an error message for UNIX-style errno indications on open or
  * create operations.
  */
-char *
+const char *
 file_open_error_message(int err, gboolean for_writing)
 {
-       char *errmsg;
+       const char *errmsg;
        static char errmsg_errno[1024+1];
 
        switch (err) {
@@ -684,7 +966,7 @@ file_open_error_message(int err, gboolean for_writing)
 #endif
 
        default:
-               snprintf(errmsg_errno, sizeof(errmsg_errno),
+               g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                                "The file \"%%s\" could not be %s: %s.",
                                for_writing ? "created" : "opened",
                                strerror(err));
@@ -698,10 +980,10 @@ file_open_error_message(int err, gboolean for_writing)
  * Return an error message for UNIX-style errno indications on write
  * operations.
  */
-char *
+const char *
 file_write_error_message(int err)
 {
-       char *errmsg;
+       const char *errmsg;
        static char errmsg_errno[1024+1];
 
        switch (err) {
@@ -717,7 +999,7 @@ file_write_error_message(int err)
 #endif
 
        default:
-               snprintf(errmsg_errno, sizeof(errmsg_errno),
+               g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                    "An error occurred while writing to the file \"%%s\": %s.",
                    strerror(err));
                errmsg = errmsg_errno;
@@ -733,6 +1015,7 @@ file_exists(const char *fname)
   struct stat   file_stat;
 
 
+#ifdef _WIN32
   /*
    * 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, ..."
@@ -740,29 +1023,50 @@ file_exists(const char *fname)
    * so this is working, but maybe not quite the way expected. ULFL
    */
    file_stat.st_ino = 1;   /* this will make things work if an error occured */
-   stat(fname, &file_stat);
+   eth_stat(fname, &file_stat);
    if (file_stat.st_ino == 0) {
        return TRUE;
    } else {
        return FALSE;
    }
+#else
+   if (eth_stat(fname, &file_stat) != 0 && errno == ENOENT) {
+       return FALSE;
+   } else {
+       return TRUE;
+   }
+#endif
 
 }
 
-
+/*
+ * Check that the from file is not the same as to file
+ * We do it here so we catch all cases ...
+ * Unfortunately, the file requester gives us an absolute file
+ * name and the read file name may be relative (if supplied on
+ * the command line), so we can't just compare paths. From Joerg Mayer.
+ */
 gboolean
 files_identical(const char *fname1, const char *fname2)
 {
     /* Two different implementations, because:
-     * - _fullpath is not available on unix 
-     * - the stat inode will not work as expected on Win32, so two different implementations.
      *
-     * XXX - will _fullpath work with UNC?
+     * - _fullpath is not available on UN*X, so we can't get full
+     *   paths and compare them (which wouldn't work with hard links
+     *   in any case);
+     *
+     * - st_ino isn't filled in with a meaningful value on Windows.
      */
 #ifdef _WIN32
     char full1[MAX_PATH], full2[MAX_PATH];
 
-
+    /*
+     * Get the absolute full paths of the file and compare them.
+     * That won't work if you have hard links, but those aren't
+     * much used on Windows, even though NTFS supports them.
+     *
+     * XXX - will _fullpath work with UNC?
+     */
     if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
         return FALSE;
     }
@@ -770,37 +1074,24 @@ files_identical(const char *fname1, const char *fname2)
     if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
         return FALSE;
     }
-    
+
     if(strcmp(full1, full2) == 0) {
         return TRUE;
     } else {
         return FALSE;
     }
 #else
-  struct stat   infile, outfile;
-
-  /*
-   * Check that the from file is not the same as to file
-   * We do it here so we catch all cases ...
-   * Unfortunately, the file requester gives us an absolute file
-   * name and the read file name may be relative (if supplied on
-   * the command line). From Joerg Mayer.
-   *
-   * 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, ..."
-   * but it *is* set to zero if stat() returns without an error,
-   * so this is not working, as it only checks if both files existing. ULFL
-   */
-   infile.st_ino = 1;   /* These prevent us from getting equality         */
-   outfile.st_ino = 2;  /* If one or other of the files is not accessible */
-   stat(cf->filename, &infile);
-   stat(fname, &outfile);
-   if (infile.st_ino == outfile.st_ino) {
-       return TRUE;
-   } else {
-       return FALSE;
-   }
-
+  struct stat   filestat1, filestat2;
+
+   /*
+    * Compare st_dev and st_ino.
+    */
+   if (eth_stat(fname1, &filestat1) == -1)
+       return FALSE;   /* can't get info about the first file */
+   if (eth_stat(fname2, &filestat2) == -1)
+       return FALSE;   /* can't get info about the second file */
+   return (filestat1.st_dev == filestat2.st_dev &&
+           filestat1.st_ino == filestat2.st_ino);
 #endif
 }