2 * Filesystem utility routines
4 * $Id: filesystem.c,v 1.12 2001/10/23 08:15:11 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@ethereal.com>
8 * Copyright 1998 Gerald Combs
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h>
44 #ifdef HAVE_SYS_STAT_H
53 #include <direct.h> /* to declare "mkdir()" on Windows */
60 #include "filesystem.h"
63 * Given a pathname, return a pointer to the last pathname separator
64 * character in the pathname, or NULL if the pathname contains no
68 find_last_pathname_separator(char *path)
76 * We have to scan for '\' or '/'.
77 * Get to the end of the string.
79 separator = path + strlen(path); /* points to ending '\0' */
80 while (separator > path) {
82 if (c == '\\' || c == '/')
83 return separator; /* found it */
87 * OK, we didn't find any, so no directories - but there might
88 * be a drive letter....
90 return strchr(path, ':');
92 separator = strrchr(path, '/');
98 * Given a pathname, return the last component.
101 get_basename(char *path)
105 filename = find_last_pathname_separator(path);
106 if (filename == NULL) {
108 * There're no directories, drive letters, etc. in the
109 * name; the pathname *is* the file name.
114 * Skip past the pathname or drive letter separator.
122 * Given a pathname, return a string containing everything but the
123 * last component. NOTE: this overwrites the pathname handed into
127 get_dirname(char *path)
131 separator = find_last_pathname_separator(path);
132 if (separator == NULL) {
134 * There're no directories, drive letters, etc. in the
135 * name; there is no directory path to return.
141 * Get rid of the last pathname separator and the final file
147 * "path" now contains the pathname of the directory containing
148 * the file/directory to which it referred.
154 * Given a pathname, return:
156 * the errno, if an attempt to "stat()" the file fails;
158 * EISDIR, if the attempt succeeded and the file turned out
161 * 0, if the attempt succeeded and the file turned out not
166 * Visual C++ on Win32 systems doesn't define these. (Old UNIX systems don't
167 * define them either.)
169 * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
172 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
175 #define S_IFIFO _S_IFIFO
178 #define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)
181 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
185 test_for_directory(const char *path)
189 if (stat(path, &statb) < 0)
192 if (S_ISDIR(statb.st_mode))
199 * Get the directory in which Ethereal's global configuration and data
203 get_datafile_dir(void)
206 char prog_pathname[_MAX_PATH+2];
208 size_t datafile_dir_len;
209 static char *datafile_dir;
212 * Have we already gotten the pathname?
213 * If so, just return it.
215 if (datafile_dir != NULL)
220 * Start out by assuming it's the default installation directory.
222 datafile_dir = "C:\\Program Files\\Ethereal\\";
225 * Now we attempt to get the full pathname of the currently running
226 * program, under the assumption that we're running an installed
227 * version of the program. If we fail, we don't change "datafile_dir",
228 * and thus end up using DATAFILE_DIR.
230 * XXX - does NSIS put the installation directory into
231 * "\HKEY_LOCAL_MACHINE\SOFTWARE\Ethereal\InstallDir"?
232 * If so, perhaps we should read that from the registry,
235 if (GetModuleFileName(NULL, prog_pathname, sizeof prog_pathname) != 0) {
237 * If the program is an installed version, the full pathname
238 * includes the pathname of the directory in which it was
239 * installed; get that directory's pathname, and construct
240 * from it the pathname of the directory in which the
241 * plugins were installed.
243 * First, find the last "\\" in the directory, as that
244 * marks the end of the directory pathname.
246 * XXX - Can the pathname be something such as
247 * "C:ethereal.exe"? Or is it always a full pathname
248 * beginning with "\\" after the drive letter?
250 dir_end = strrchr(prog_pathname, '\\');
251 if (dir_end != NULL) {
253 * Found it - now figure out how long the datafile
254 * directory pathname will be.
256 datafile_dir_len = (dir_end - prog_pathname);
259 * Allocate a buffer for the plugin directory
260 * pathname, and construct it.
262 datafile_dir = g_malloc(datafile_dir_len + 1);
263 strncpy(datafile_dir, prog_pathname, datafile_dir_len);
264 datafile_dir[datafile_dir_len] = '\0';
270 * Just use DATAFILE_DIR, as that's what the configure script
278 * Get the directory in which files that, at least on UNIX, are
279 * system files (such as "/etc/ethers") are stored; on Windows,
280 * there's no "/etc" directory, so we get them from the Ethereal
281 * global configuration and data file directory.
284 get_systemfile_dir(void)
287 return get_datafile_dir();
294 * Name of directory, under the user's home directory, in which
295 * personal configuration files are stored.
297 * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
298 * it ".ethereal" for now.
300 #define PF_DIR ".ethereal"
303 * Get the directory in which personal configuration files reside;
304 * it's PF_DIR, under the user's home directory.
307 get_persconffile_dir(void)
313 static char *pf_dir = NULL;
315 /* Return the cached value, if available */
321 * Use %USERPROFILE%, so that configuration files are stored
322 * in the user profile, rather than in the home directory.
323 * The Windows convention is to store configuration information
324 * in the user profile, and doing so means you can use
325 * Ethereal even if the home directory is an inaccessible
328 homedir = getenv("USERPROFILE");
329 if (homedir == NULL) {
331 * Give up and use "C:".
337 * If $HOME is set, use that.
339 homedir = getenv("HOME");
340 if (homedir == NULL) {
342 * Get their home directory from the password file.
343 * If we can't even find a password file entry for them,
346 pwd = getpwuid(getuid());
349 * This is cached, so we don't need to worry
350 * about allocating multiple ones of them.
352 homedir = g_strdup(pwd->pw_dir);
358 pf_dir = g_malloc(strlen(homedir) + strlen(PF_DIR) + 2);
359 sprintf(pf_dir, "%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
364 * Create the directory that holds personal configuration files, if
365 * necessary. If we attempted to create it, and failed, return -1 and
366 * set "*pf_dir_path_return" to the pathname of the directory; otherwise,
370 create_persconffile_dir(const char **pf_dir_path_return)
372 const char *pf_dir_path;
376 pf_dir_path = get_persconffile_dir();
377 if (stat(pf_dir_path, &s_buf) != 0) {
379 ret = mkdir(pf_dir_path);
381 ret = mkdir(pf_dir_path, 0755);
385 * Something with that pathname exists; if it's not
386 * a directory, we'll get an error if we try to put
387 * something in it, so we don't fail here, we wait
388 * for that attempt fo fail.
393 *pf_dir_path_return = pf_dir_path;