Removed some more "statement not reached" warnings.
[obnox/wireshark/wip.git] / epan / filesystem.c
index 6095244faf9dd89f810012d8e33619e98df1b9bc..86c37b5f0558aae2fb6c2f42bdaec25f270d2de3 100644 (file)
 # include "config.h"
 #endif
 
+#ifdef HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include "privileges.h"
 #include <wiretap/file_util.h>
 
+#define PROFILES_DIR    "profiles"
 #define U3_MY_CAPTURES  "\\My Captures"
 
+char *persconffile_dir = NULL;
+char *persdatafile_dir = NULL;
+char *persconfprofile = NULL;
+
 /*
  * Given a pathname, return a pointer to the last pathname separator
  * character in the pathname, or NULL if the pathname contains no
@@ -208,8 +218,16 @@ test_for_fifo(const char *path)
                return 0;
 }
 
+/*
+ * Directory from which the executable came.
+ */
 static char *progfile_dir;
 
+/*
+ * TRUE if we're running from the build directory.
+ */
+static gboolean running_in_build_directory_flag = FALSE;
+
 /*
  * Get the pathname of the directory from which the executable came,
  * and save it for future use.  Returns NULL on success, and a
@@ -316,6 +334,19 @@ init_progfile_dir(const char *arg0
        size_t path_component_len;
        char *retstr;
 
+       /*
+        * Check whether WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set in the
+        * environment; if so, set running_in_build_directory_flag if we
+        * weren't started with special privileges.  (If we were started
+        * with special privileges, it's not safe to allow the user to point
+        * us to some other directory; running_in_build_directory_flag, when
+        * set, causes us to look for plugins and the like in the build
+        * directory.)
+        */
+       if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
+           && !started_with_special_privs())
+               running_in_build_directory_flag = TRUE;
+
        /*
         * Try to figure out the directory in which the currently running
         * program resides, given the argv[0] it was started with.  That
@@ -355,10 +386,7 @@ init_progfile_dir(const char *arg0
                        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);
+               path = g_strdup_printf("%s/%s", curdir, arg0);
                g_free(curdir);
                prog_pathname = path;
        } else {
@@ -380,8 +408,8 @@ init_progfile_dir(const char *arg0
                                    + strlen(arg0) + 1);
                                memcpy(path, path_start, path_component_len);
                                path[path_component_len] = '\0';
-                               strcat(path, "/");
-                               strcat(path, arg0);
+                               strncat(path, "/", 2);
+                               strncat(path, arg0, strlen(arg0) + 1);
                                if (access(path, X_OK) == 0) {
                                        /*
                                         * Found it!
@@ -448,6 +476,20 @@ init_progfile_dir(const char *arg0
                                 * artifact of libtool.
                                 */
                                *dir_end = '\0';
+
+                               /*
+                                * This presumably means we're run from
+                                * the libtool wrapper, which probably
+                                * means we're being run from the build
+                                * directory.  If we weren't started
+                                * with special privileges, set
+                                * running_in_build_directory_flag.
+                                *
+                                * XXX - should we check whether what
+                                * follows ".libs/" begins with "lt-"?
+                                */
+                               if (!started_with_special_privs())
+                                       running_in_build_directory_flag = TRUE;
                        }
                }
 
@@ -486,9 +528,9 @@ get_progfile_dir(void)
  * process resides.
  *
  * On UN*X, we use the DATAFILE_DIR value supplied by the configure
- * script, unless the WIRESHARK_RUN_FROM_BUILD_DIRECTORY environment
- * variable is set, in which case we use the directory in which the
- * executable for this process resides.
+ * script, unless we think we're being run from the build directory,
+ * in which case we use the directory in which the executable for this
+ * process resides.
  *
  * XXX - if we ever make libwireshark a real library, used by multiple
  * applications (more than just TShark and versions of Wireshark with
@@ -559,13 +601,12 @@ get_datafile_dir(void)
                }
        }
 #else
-       if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
-           && !started_with_special_privs() && progfile_dir != NULL) {
+       if (running_in_build_directory_flag && progfile_dir != NULL) {
                /*
-                * WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set, and
-                * we weren't started with special privileges, and
-                * we were able to determine the directory in which
-                * the program was found, so use that.
+                * We're (probably) being run from the build directory and
+                * weren't started with special privileges, and we were
+                * able to determine the directory in which the program
+                * was found, so use that.
                 */
                datafile_dir = progfile_dir;
        } else {
@@ -580,33 +621,28 @@ get_datafile_dir(void)
        return datafile_dir;
 }
 
+#ifdef HAVE_PLUGINS
 /*
  * Find the directory where the plugins are stored.
  *
  * On Windows, we use the "plugin" subdirectory of the datafile directory.
  *
  * On UN*X, we use the PLUGIN_DIR value supplied by the configure
- * script, unless the WIRESHARK_RUN_FROM_BUILD_DIRECTORY environment
- * variable is set, in which case we use the "plugin" subdirectory of
- * the datafile directory.
+ * 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 both cases, we then use the subdirectory of that directory whose
  * name is the version number.
  *
- * XXX - if WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set, perhaps we
+ * 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.
  */
-static const char *plugin_dir;
+static const char *plugin_dir = NULL;
 
-/*
- * TRUE if we're running from the build directory.
- */
-static gboolean running_in_build_directory_flag = FALSE;
-
-void
+static void
 init_plugin_dir(void)
 {
 #ifdef _WIN32
@@ -643,26 +679,19 @@ init_plugin_dir(void)
                running_in_build_directory_flag = TRUE;
        }
 #else
-       if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
-           && !started_with_special_privs()) {
+       if (running_in_build_directory_flag) {
                /*
-                * WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set, and
-                * we weren't started with special privileges, so
-                * we'll use the "plugins" subdirectory of the
-                * datafile directory (the datafile directory is
-                * the build 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.  (If we were started with special
-                * privileges, it's not safe to allow the user to
-                * point us to some other directory.)
+                * 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 datafile directory
+                * (the datafile directory is the build directory).
                 */
                plugin_dir = g_strdup_printf("%s/plugins", get_datafile_dir());
-               running_in_build_directory_flag = TRUE;
        } else
                plugin_dir = PLUGIN_DIR;
 #endif
 }
+#endif /* HAVE_PLUGINS */
 
 /*
  * Get the directory in which the plugins are stored.
@@ -670,7 +699,12 @@ init_plugin_dir(void)
 const char *
 get_plugin_dir(void)
 {
+#ifdef HAVE_PLUGINS
+       if (!plugin_dir) init_plugin_dir();
        return plugin_dir;
+#else
+        return NULL;
+#endif
 }
 
 /*
@@ -713,7 +747,7 @@ get_systemfile_dir(void)
 #define PF_DIR ".wireshark"
 #endif
 
-#ifdef WIN32
+#ifdef _WIN32
 /* utf8 version of getenv, needed to get win32 filename paths */
 char *getenv_utf8(const char *varname)
 {
@@ -749,6 +783,32 @@ char *getenv_utf8(const char *varname)
 }
 #endif
 
+void
+set_profile_name(const gchar *profilename)
+{
+       if (persconfprofile) {
+               g_free (persconfprofile);
+       }
+
+       if (profilename && strlen(profilename) > 0 && 
+           strcmp(profilename, DEFAULT_PROFILE) != 0) {
+               persconfprofile = g_strdup (profilename);
+       } else {
+               /* Default Profile */
+               persconfprofile = NULL;
+       }
+}
+
+const char *
+get_profile_name(void)
+{
+       if (persconfprofile) {
+               return persconfprofile;
+       } else {
+               return DEFAULT_PROFILE;
+       }
+}
+
 /*
  * Get the directory in which personal configuration files reside;
  * in UNIX-compatible systems, it's ".wireshark", under the user's home
@@ -757,7 +817,7 @@ char *getenv_utf8(const char *varname)
  * (which is what %APPDATA% normally is on Windows 2000).
  */
 static const char *
-get_persconffile_dir(void)
+get_persconffile_dir_no_profile(void)
 {
 #ifdef _WIN32
        char *appdatadir;
@@ -767,11 +827,10 @@ get_persconffile_dir(void)
        const char *homedir;
        struct passwd *pwd;
 #endif
-       static char *pf_dir = NULL;
 
        /* Return the cached value, if available */
-       if (pf_dir != NULL)
-               return pf_dir;
+       if (persconffile_dir != NULL)
+               return persconffile_dir;
 
 #ifdef _WIN32
        /*
@@ -782,7 +841,7 @@ get_persconffile_dir(void)
                /*
                 * We are; use the U3 application data path.
                 */
-               pf_dir = u3appdatapath;
+               persconffile_dir = u3appdatapath;
        } else {
                /*
                 * Use %APPDATA% or %USERPROFILE%, so that configuration
@@ -797,8 +856,8 @@ get_persconffile_dir(void)
                        /*
                         * Concatenate %APPDATA% with "\Wireshark".
                         */
-                       pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
-                           appdatadir, PF_DIR);
+                       persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
+                                                          appdatadir, PF_DIR);
                } else {
                        /*
                         * OK, %APPDATA% wasn't set, so use
@@ -806,14 +865,14 @@ get_persconffile_dir(void)
                         */
                        userprofiledir = getenv_utf8("USERPROFILE");
                        if (userprofiledir != NULL) {
-                               pf_dir = g_strdup_printf(
+                               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:".
                                 */
-                               pf_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
+                               persconffile_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
                        }
                }
        }
@@ -838,10 +897,125 @@ get_persconffile_dir(void)
                } else
                        homedir = "/tmp";
        }
-       pf_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
+       persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
 #endif
 
-       return pf_dir;
+       return persconffile_dir;
+}
+
+const char *
+get_profiles_dir(void)
+{
+       static char *profiles_dir = NULL;
+
+       if (profiles_dir) {
+               g_free (profiles_dir);
+       }
+
+       profiles_dir = g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
+                                       G_DIR_SEPARATOR_S, PROFILES_DIR);
+
+       return profiles_dir;
+}
+
+static const char *
+get_persconffile_dir(const gchar *profilename)
+{
+       static char *persconffile_profile_dir = NULL;
+
+       if (persconffile_profile_dir) {
+               g_free (persconffile_profile_dir);
+       }
+
+       if (profilename && strlen(profilename) > 0 &&
+           strcmp(profilename, DEFAULT_PROFILE) != 0) {
+         persconffile_profile_dir = g_strdup_printf ("%s%s%s", get_profiles_dir (), 
+                                                     G_DIR_SEPARATOR_S, profilename);
+       } else {
+         persconffile_profile_dir = g_strdup_printf (get_persconffile_dir_no_profile ());
+       }
+
+       return persconffile_profile_dir;
+}
+
+gboolean
+profile_exists(const gchar *profilename)
+{
+       if (test_for_directory (get_persconffile_dir (profilename)) == EISDIR) {
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static int
+delete_directory (const char *directory, char **pf_dir_path_return)
+{
+       ETH_DIR *dir;
+       ETH_DIRENT *file;
+       gchar *filename;
+       int ret = 0;
+
+       if ((dir = eth_dir_open(directory, 0, NULL)) != NULL) {
+               while ((file = eth_dir_read_name(dir)) != NULL) {
+                       filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S, 
+                                                   eth_dir_get_name(file));
+                       if (test_for_directory(filename) != EISDIR) {
+                               ret = eth_remove(filename);
+#if 0
+                       } else {
+                               /* The user has manually created a directory in the profile directory */
+                               /* I do not want to delete the directory recursively yet */
+                               ret = delete_directory (filename, pf_dir_path_return);
+#endif
+                       }
+                       if (ret != 0) {
+                               *pf_dir_path_return = filename;
+                               break;
+                       }
+                       g_free (filename);
+               }
+               eth_dir_close(dir);
+       }
+
+       if (ret == 0 && (ret = eth_remove(directory)) != 0) {
+               *pf_dir_path_return = g_strdup (directory);
+       }
+
+       return ret;
+}
+
+int
+delete_persconffile_profile(const char *profilename, char **pf_dir_path_return)
+{
+       const 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);
+       }
+
+       return ret;
+}
+
+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));
+  int ret = 0;
+
+  ret = eth_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);
+  }
+
+  g_free (from_dir);
+  g_free (to_dir);
+
+  return ret;
 }
 
 /*
@@ -852,7 +1026,7 @@ get_persconffile_dir(void)
  * return 0.
  */
 int
-create_persconffile_dir(char **pf_dir_path_return)
+create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
 {
        const char *pf_dir_path;
 #ifdef _WIN32
@@ -862,7 +1036,22 @@ create_persconffile_dir(char **pf_dir_path_return)
        struct stat s_buf;
        int ret;
 
-       pf_dir_path = get_persconffile_dir();
+       if (profilename) {
+               /*
+                * Check if profiles directory exists.
+                * If not then create it.
+                */
+               pf_dir_path = get_profiles_dir ();
+               if (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
+                       ret = eth_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 (eth_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
 #ifdef _WIN32
                /*
@@ -910,6 +1099,12 @@ create_persconffile_dir(char **pf_dir_path_return)
        return ret;
 }
 
+int
+create_persconffile_dir(char **pf_dir_path_return)
+{
+  return create_persconffile_profile(persconfprofile, pf_dir_path_return);
+}
+
 /*
  * Get the (default) directory in which personal data is stored.
  *
@@ -925,37 +1120,34 @@ get_persdatafile_dir(void)
     char *u3devicedocumentpath;
     TCHAR tszPath[MAX_PATH];
        char *szPath;
-/* SHGetFolderPath is not available on MSVC 6 - without Platform SDK */
-#if 0
-       HRESULT hrRet;
-#else
-        BOOL bRet;
-#endif 
+       BOOL bRet;
+
+
+       /* Return the cached value, if available */
+       if (persdatafile_dir != NULL)
+               return persdatafile_dir;
+
        /*
         * See if we are running in a U3 environment.
         */
        u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
 
        if (u3devicedocumentpath != NULL) {
-         
-         /* the "My Captures" sub-directory is created (if it doesn't exist) 
+
+         /* the "My Captures" sub-directory is created (if it doesn't exist)
             by u3util.exe when the U3 Wireshark is first run */
-         
-         szPath = g_malloc(strlen(u3devicedocumentpath) + strlen(U3_MY_CAPTURES) + 1);
-         strcpy(szPath, u3devicedocumentpath);
-         strcat(szPath, U3_MY_CAPTURES);
 
+         szPath = g_strdup_printf("%s%s", u3devicedocumentpath, U3_MY_CAPTURES);
+
+         persdatafile_dir = szPath;
          return szPath;
 
         } else {
-#if 0
-       hrRet = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, tszPath);
-       if(hrRet == S_OK) {
-#else
-        bRet = SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE);
+       /* Hint: SHGetFolderPath is not available on MSVC 6 - without Platform SDK */
+       bRet = SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE);
        if(bRet == TRUE) {
-#endif
                szPath = utf_16to8(tszPath);
+               persdatafile_dir = szPath;
                return szPath;
        } else {
                return "";
@@ -995,10 +1187,7 @@ get_home_dir(void)
                         * This is cached, so we don't need to worry about
                         * allocating multiple ones of them.
                         */
-                       homestring =
-                           g_malloc(strlen(homedrive) + strlen(homepath) + 1);
-                       strcpy(homestring, homedrive);
-                       strcat(homestring, homepath);
+                       homestring = g_strdup_printf("%s%s", homedrive, homepath);
 
                        /*
                         * Trim off any trailing slash or backslash.
@@ -1036,7 +1225,7 @@ get_home_dir(void)
  * from earlier versions can be read.
  */
 char *
-get_persconffile_path(const char *filename, gboolean for_writing
+get_persconffile_path(const char *filename, gboolean from_profile, gboolean for_writing
 #ifndef _WIN32
        _U_
 #endif
@@ -1048,8 +1237,13 @@ get_persconffile_path(const char *filename, gboolean for_writing
        char *old_path;
 #endif
 
-       path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_persconffile_dir(),
-           filename);
+       if (from_profile) {
+         path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
+                                get_persconffile_dir(persconfprofile), filename);
+       } else {
+         path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
+                                get_persconffile_dir(NULL), filename);
+       }
 #ifdef _WIN32
        if (!for_writing) {
                if (eth_stat(path, &s_buf) != 0 && errno == ENOENT) {
@@ -1075,6 +1269,64 @@ get_persconffile_path(const char *filename, gboolean for_writing
        return path;
 }
 
+/*
+ * process command line option belonging to the filesystem settings
+ * (move this e.g. to main.c and have set_persconffile_dir() instead in this file?)
+ */
+int
+filesystem_opt(int opt _U_, const char *optarg)
+{
+  gchar *p, *colonp;
+
+  colonp = strchr(optarg, ':');
+  if (colonp == NULL) {
+    return 1;
+  }
+
+  p = colonp;
+  *p++ = '\0';
+
+  /*
+   * Skip over any white space (there probably won't be any, but
+   * as we allow it in the preferences file, we might as well
+   * allow it here).
+   */
+  while (isspace((guchar)*p))
+    p++;
+  if (*p == '\0') {
+    /*
+     * Put the colon back, so if our caller uses, in an
+     * error message, the string they passed us, the message
+     * looks correct.
+     */
+    *colonp = ':';
+    return 1;
+  }
+
+  /* directory should be existing */
+  /* XXX - is this a requirement? */
+  if(test_for_directory(p) != EISDIR) {
+    /*
+     * Put the colon back, so if our caller uses, in an
+     * error message, the string they passed us, the message
+     * looks correct.
+     */
+    *colonp = ':';
+    return 1;
+  }
+
+  if (strcmp(optarg,"persconf") == 0) {
+    persconffile_dir = p;
+  } else if (strcmp(optarg,"persdata") == 0) {
+    persdatafile_dir = p;
+  /* XXX - might need to add the temp file path */
+  } else {
+    return 1;
+  }
+  *colonp = ':'; /* put the colon back */
+  return 0;
+}
+
 /*
  * Construct the path name of a global configuration file, given the
  * file name.
@@ -1144,6 +1396,10 @@ file_open_error_message(int err, gboolean for_writing)
                break;
 #endif
 
+       case EINVAL:
+               errmsg = "The file \"%s\" could not be created because an invalid filename was specified.";
+               break;
+
        default:
                g_snprintf(errmsg_errno, sizeof(errmsg_errno),
                                "The file \"%%s\" could not be %s: %s.",