In Solaris, the second argument to dladdr() is just a void *, not a
[obnox/wireshark/wip.git] / epan / filesystem.c
1 /* filesystem.c
2  * Filesystem utility routines
3  *
4  * $Id$
5  *
6  * Wireshark - Network traffic analyzer
7  * By Gerald Combs <gerald@wireshark.org>
8  * Copyright 1998 Gerald Combs
9  *
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.
14  *
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.
19  *
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.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 # include "config.h"
27 #endif
28
29 #ifdef HAVE_DIRENT_H
30 #include <dirent.h>
31 #endif
32
33 #include <stdio.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38
39 #include <glib.h>
40
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44
45 #ifdef HAVE_FCNTL_H
46 #include <fcntl.h>
47 #endif
48
49 #ifdef HAVE_SYS_STAT_H
50 #include <sys/stat.h>
51 #endif
52
53 #ifdef _WIN32
54 #include <windows.h>
55 #include <tchar.h>
56 #include <shlobj.h>
57 #include <wsutil/unicode-utils.h>
58 #else /* _WIN32 */
59 #ifdef DLADDR_FINDS_EXECUTABLE_PATH
60 #include <dlfcn.h>
61 #endif /* DLADDR_FINDS_EXECUTABLE_PATH */
62 #include <pwd.h>
63 #endif /* _WIN32 */
64
65 #include "filesystem.h"
66 #include "report_err.h"
67 #include <wsutil/privileges.h>
68 #include <wsutil/file_util.h>
69
70 #include <wiretap/wtap.h>       /* for WTAP_ERR_SHORT_WRITE */
71
72 #define PROFILES_DIR    "profiles"
73 #define U3_MY_CAPTURES  "\\My Captures"
74
75 char *persconffile_dir = NULL;
76 char *persdatafile_dir = NULL;
77 char *persconfprofile = NULL;
78
79 /*
80  * Given a pathname, return a pointer to the last pathname separator
81  * character in the pathname, or NULL if the pathname contains no
82  * separators.
83  */
84 static char *
85 find_last_pathname_separator(const char *path)
86 {
87         char *separator;
88
89 #ifdef _WIN32
90         char c;
91
92         /*
93          * We have to scan for '\' or '/'.
94          * Get to the end of the string.
95          */
96         separator = strchr(path, '\0');         /* points to ending '\0' */
97         while (separator > path) {
98                 c = *--separator;
99                 if (c == '\\' || c == '/')
100                         return separator;       /* found it */
101         }
102
103         /*
104          * OK, we didn't find any, so no directories - but there might
105          * be a drive letter....
106          */
107         return strchr(path, ':');
108 #else
109         separator = strrchr(path, '/');
110 #endif
111         return separator;
112 }
113
114 /*
115  * Given a pathname, return the last component.
116  */
117 const char *
118 get_basename(const char *path)
119 {
120         const char *filename;
121
122         g_assert(path != NULL);
123         filename = find_last_pathname_separator(path);
124         if (filename == NULL) {
125                 /*
126                  * There're no directories, drive letters, etc. in the
127                  * name; the pathname *is* the file name.
128                  */
129                 filename = path;
130         } else {
131                 /*
132                  * Skip past the pathname or drive letter separator.
133                  */
134                 filename++;
135         }
136         return filename;
137 }
138
139 /*
140  * Given a pathname, return a string containing everything but the
141  * last component.  NOTE: this overwrites the pathname handed into
142  * it....
143  */
144 char *
145 get_dirname(char *path)
146 {
147         char *separator;
148
149         g_assert(path != NULL);
150         separator = find_last_pathname_separator(path);
151         if (separator == NULL) {
152                 /*
153                  * There're no directories, drive letters, etc. in the
154                  * name; there is no directory path to return.
155                  */
156                 return NULL;
157         }
158
159         /*
160          * Get rid of the last pathname separator and the final file
161          * name following it.
162          */
163         *separator = '\0';
164
165         /*
166          * "path" now contains the pathname of the directory containing
167          * the file/directory to which it referred.
168          */
169         return path;
170 }
171
172 /*
173  * Given a pathname, return:
174  *
175  *      the errno, if an attempt to "stat()" the file fails;
176  *
177  *      EISDIR, if the attempt succeeded and the file turned out
178  *      to be a directory;
179  *
180  *      0, if the attempt succeeded and the file turned out not
181  *      to be a directory.
182  */
183
184 /*
185  * Visual C++ on Win32 systems doesn't define these.  (Old UNIX systems don't
186  * define them either.)
187  *
188  * Visual C++ on Win32 systems doesn't define S_IFIFO, it defines _S_IFIFO.
189  */
190 #ifndef S_ISREG
191 #define S_ISREG(mode)   (((mode) & S_IFMT) == S_IFREG)
192 #endif
193 #ifndef S_IFIFO
194 #define S_IFIFO _S_IFIFO
195 #endif
196 #ifndef S_ISFIFO
197 #define S_ISFIFO(mode)  (((mode) & S_IFMT) == S_IFIFO)
198 #endif
199 #ifndef S_ISDIR
200 #define S_ISDIR(mode)   (((mode) & S_IFMT) == S_IFDIR)
201 #endif
202
203 int
204 test_for_directory(const char *path)
205 {
206         struct stat statb;
207
208         if (ws_stat(path, &statb) < 0)
209                 return errno;
210
211         if (S_ISDIR(statb.st_mode))
212                 return EISDIR;
213         else
214                 return 0;
215 }
216
217 int
218 test_for_fifo(const char *path)
219 {
220         struct stat statb;
221
222         if (ws_stat(path, &statb) < 0)
223                 return errno;
224
225         if (S_ISFIFO(statb.st_mode))
226                 return ESPIPE;
227         else
228                 return 0;
229 }
230
231 /*
232  * Directory from which the executable came.
233  */
234 static char *progfile_dir;
235
236 /*
237  * TRUE if we're running from the build directory and we aren't running
238  * with special privileges.
239  */
240 static gboolean running_in_build_directory_flag = FALSE;
241
242 /*
243  * Get the pathname of the directory from which the executable came,
244  * and save it for future use.  Returns NULL on success, and a
245  * g_mallocated string containing an error on failure.
246  */
247 char *
248 init_progfile_dir(const char *arg0
249 #ifdef _WIN32
250         _U_
251 #endif
252 , void *main_addr
253 #if defined(_WIN32) || !defined(DLADDR_FINDS_EXECUTABLE_PATH)
254         _U_
255 #endif
256 )
257 {
258         char *dir_end;
259         char *path;
260 #ifdef _WIN32
261         TCHAR prog_pathname_w[_MAX_PATH+2];
262         size_t progfile_dir_len;
263         char *prog_pathname;
264         DWORD error;
265         TCHAR *msg_w;
266         guchar *msg;
267         size_t msglen;
268
269         /*
270          * Attempt to get the full pathname of the currently running
271          * program.
272          */
273         if (GetModuleFileName(NULL, prog_pathname_w, sizeof prog_pathname_w) != 0) {
274                 /*
275                  * XXX - Should we use g_utf16_to_utf8(), as in
276                  * getenv_utf8()?
277                  */
278                 prog_pathname = utf_16to8(prog_pathname_w);
279                 /*
280                  * We got it; strip off the last component, which would be
281                  * the file name of the executable, giving us the pathname
282                  * of the directory where the executable resies
283                  *
284                  * First, find the last "\" in the directory, as that
285                  * marks the end of the directory pathname.
286                  *
287                  * XXX - Can the pathname be something such as
288                  * "C:wireshark.exe"?  Or is it always a full pathname
289                  * beginning with "\" after the drive letter?
290                  */
291                 dir_end = strrchr(prog_pathname, '\\');
292                 if (dir_end != NULL) {
293                         /*
294                          * Found it - now figure out how long the program
295                          * directory pathname will be.
296                          */
297                         progfile_dir_len = (dir_end - prog_pathname);
298
299                         /*
300                          * Allocate a buffer for the program directory
301                          * pathname, and construct it.
302                          */
303                         path = g_malloc(progfile_dir_len + 1);
304                         strncpy(path, prog_pathname, progfile_dir_len);
305                         path[progfile_dir_len] = '\0';
306                         progfile_dir = path;
307
308                         return NULL;    /* we succeeded */
309                 } else {
310                         /*
311                          * OK, no \ - what do we do now?
312                          */
313                         return g_strdup_printf("No \\ in executable pathname \"%s\"",
314                             prog_pathname);
315                 }
316         } else {
317                 /*
318                  * Oh, well.  Return an indication of the error.
319                  */
320                 error = GetLastError();
321                 if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
322                     NULL, error, 0, (LPTSTR) &msg_w, 0, NULL) == 0) {
323                         /*
324                          * Gak.  We can't format the message.
325                          */
326                         return g_strdup_printf("GetModuleFileName failed: %u (FormatMessage failed: %u)",
327                             error, GetLastError());
328                 }
329                 msg = utf_16to8(msg_w);
330                 LocalFree(msg_w);
331                 /*
332                  * "FormatMessage()" "helpfully" sticks CR/LF at the
333                  * end of the message.  Get rid of it.
334                  */
335                 msglen = strlen(msg);
336                 if (msglen >= 2) {
337                         msg[msglen - 1] = '\0';
338                         msg[msglen - 2] = '\0';
339                 }
340                 return g_strdup_printf("GetModuleFileName failed: %s (%u)",
341                     msg, error);
342         }
343 #else
344 #ifdef DLADDR_FINDS_EXECUTABLE_PATH
345         Dl_info info;
346 #endif
347         char *prog_pathname;
348         char *curdir;
349         long path_max;
350         char *pathstr;
351         char *path_start, *path_end;
352         size_t path_component_len;
353         char *retstr;
354
355         /*
356          * Check whether WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set in the
357          * environment; if so, set running_in_build_directory_flag if we
358          * weren't started with special privileges.  (If we were started
359          * with special privileges, it's not safe to allow the user to point
360          * us to some other directory; running_in_build_directory_flag, when
361          * set, causes us to look for plugins and the like in the build
362          * directory.)
363          */
364         if (getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
365             && !started_with_special_privs())
366                 running_in_build_directory_flag = TRUE;
367
368 #ifdef DLADDR_FINDS_EXECUTABLE_PATH
369         /*
370          * Try to use dladdr() to find the pathname of the executable.
371          */
372         if (dladdr(main_addr, &info) && info.dli_fname[0] == '/') {
373                 /*
374                  * dladdr() succeeded, and we got an absolute path
375                  * for the module containing main() (I don't know
376                  * whether it's guaranteed to return an absolute path
377                  * on all platforms), so we'll use that as the
378                  * executable image's path.
379                  */
380                 prog_pathname = g_strdup(info.dli_fname);
381         } else
382 #endif
383         {
384         /*
385          * Try to figure out the directory in which the currently running
386          * program resides, given the argv[0] it was started with.  That
387          * might be the absolute path of the program, or a path relative
388          * to the current directory of the process that started it, or
389          * just a name for the program if it was started from the command
390          * line and was searched for in $PATH.  It's not guaranteed to be
391          * any of those, however, so there are no guarantees....
392          */
393         if (arg0[0] == '/') {
394                 /*
395                  * It's an absolute path.
396                  */
397                 prog_pathname = g_strdup(arg0);
398         } else if (strchr(arg0, '/') != NULL) {
399                 /*
400                  * It's a relative path, with a directory in it.
401                  * Get the current directory, and combine it
402                  * with that directory.
403                  */
404                 path_max = pathconf(".", _PC_PATH_MAX);
405                 if (path_max == -1) {
406                         /*
407                          * We have no idea how big a buffer to
408                          * allocate for the current directory.
409                          */
410                         return g_strdup_printf("pathconf failed: %s\n",
411                             strerror(errno));
412                 }
413                 curdir = g_malloc(path_max);
414                 if (getcwd(curdir, path_max) == NULL) {
415                         /*
416                          * It failed - give up, and just stick
417                          * with DATAFILE_DIR.
418                          */
419                         g_free(curdir);
420                         return g_strdup_printf("getcwd failed: %s\n",
421                             strerror(errno));
422                 }
423                 path = g_strdup_printf("%s/%s", curdir, arg0);
424                 g_free(curdir);
425                 prog_pathname = path;
426         } else {
427                 /*
428                  * It's just a file name.
429                  * Search the path for a file with that name
430                  * that's executable.
431                  */
432                 prog_pathname = NULL;   /* haven't found it yet */
433                 pathstr = getenv("PATH");
434                 path_start = pathstr;
435                 if (path_start != NULL) {
436                         while (*path_start != '\0') {
437                                 path_end = strchr(path_start, ':');
438                                 if (path_end == NULL)
439                                         path_end = path_start + strlen(path_start);
440                                 path_component_len = path_end - path_start;
441                                 path = g_malloc(path_component_len + 1
442                                     + strlen(arg0) + 1);
443                                 memcpy(path, path_start, path_component_len);
444                                 path[path_component_len] = '\0';
445                                 strncat(path, "/", 2);
446                                 strncat(path, arg0, strlen(arg0) + 1);
447                                 if (access(path, X_OK) == 0) {
448                                         /*
449                                          * Found it!
450                                          */
451                                         prog_pathname = path;
452                                         break;
453                                 }
454
455                                 /*
456                                  * That's not it.  If there are more
457                                  * path components to test, try them.
458                                  */
459                                 if (*path_end == '\0') {
460                                         /*
461                                          * There's nothing more to try.
462                                          */
463                                         break;
464                                 }
465                                 if (*path_end == ':')
466                                         path_end++;
467                                 path_start = path_end;
468                                 g_free(path);
469                         }
470                         if (prog_pathname == NULL) {
471                                 /*
472                                  * Program not found in path.
473                                  */
474                                 return g_strdup_printf("\"%s\" not found in \"%s\"",
475                                     arg0, pathstr);
476                         }
477                 } else {
478                         /*
479                          * PATH isn't set.
480                          * XXX - should we pick a default?
481                          */
482                         return g_strdup("PATH isn't set");
483                 }
484         }
485         }
486
487         /*
488          * OK, we have what we think is the pathname
489          * of the program.
490          *
491          * First, find the last "/" in the directory,
492          * as that marks the end of the directory pathname.
493          */
494         dir_end = strrchr(prog_pathname, '/');
495         if (dir_end != NULL) {
496                 /*
497                  * Found it.  Strip off the last component,
498                  * as that's the path of the program.
499                  */
500                 *dir_end = '\0';
501
502                 /*
503                  * Is there a "/.libs" at the end?
504                  */
505                 dir_end = strrchr(prog_pathname, '/');
506                 if (dir_end != NULL) {
507                         if (strcmp(dir_end, "/.libs") == 0) {
508                                 /*
509                                  * Yup, it's ".libs".
510                                  * Strip that off; it's an
511                                  * artifact of libtool.
512                                  */
513                                 *dir_end = '\0';
514
515                                 /*
516                                  * This presumably means we're run from
517                                  * the libtool wrapper, which probably
518                                  * means we're being run from the build
519                                  * directory.  If we weren't started
520                                  * with special privileges, set
521                                  * running_in_build_directory_flag.
522                                  *
523                                  * XXX - should we check whether what
524                                  * follows ".libs/" begins with "lt-"?
525                                  */
526                                 if (!started_with_special_privs())
527                                         running_in_build_directory_flag = TRUE;
528                         }
529                 }
530
531                 /*
532                  * OK, we have the path we want.
533                  */
534                 progfile_dir = prog_pathname;
535                 return NULL;
536         } else {
537                 /*
538                  * This "shouldn't happen"; we apparently
539                  * have no "/" in the pathname.
540                  * Just free up prog_pathname.
541                  */
542                 retstr = g_strdup_printf("No / found in \"%s\"", prog_pathname);
543                 g_free(prog_pathname);
544                 return retstr;
545         }
546 #endif
547 }
548
549 /*
550  * Get the directory in which the program resides.
551  */
552 const char *
553 get_progfile_dir(void)
554 {
555         return progfile_dir;
556 }
557
558 /*
559  * Get the directory in which the global configuration and data files are
560  * stored.
561  *
562  * On Windows, we use the directory in which the executable for this
563  * process resides.
564  *
565  * On UN*X, we use the DATAFILE_DIR value supplied by the configure
566  * script, unless we think we're being run from the build directory,
567  * in which case we use the directory in which the executable for this
568  * process resides.
569  *
570  * XXX - if we ever make libwireshark a real library, used by multiple
571  * applications (more than just TShark and versions of Wireshark with
572  * various UIs), should the configuration files belong to the library
573  * (and be shared by all those applications) or to the applications?
574  *
575  * If they belong to the library, that could be done on UNIX by the
576  * configure script, but it's trickier on Windows, as you can't just
577  * use the pathname of the executable.
578  *
579  * If they belong to the application, that could be done on Windows
580  * by using the pathname of the executable, but we'd have to have it
581  * passed in as an argument, in some call, on UNIX.
582  *
583  * Note that some of those configuration files might be used by code in
584  * libwireshark, some of them might be used by dissectors (would they
585  * belong to libwireshark, the application, or a separate library?),
586  * and some of them might be used by other code (the Wireshark preferences
587  * file includes resolver preferences that control the behavior of code
588  * in libwireshark, dissector preferences, and UI preferences, for
589  * example).
590  */
591 const char *
592 get_datafile_dir(void)
593 {
594 #ifdef _WIN32
595         char *u3deviceexecpath;
596 #endif
597         static char *datafile_dir = NULL;
598
599         if (datafile_dir != NULL)
600                 return datafile_dir;
601
602 #ifdef _WIN32
603         /*
604          * See if we are running in a U3 environment.
605          */
606         u3deviceexecpath = getenv_utf8("U3_DEVICE_EXEC_PATH");
607
608         if (u3deviceexecpath != NULL) {
609                 /*
610                  * We are; use the U3 device executable path.
611                  */
612                 datafile_dir = u3deviceexecpath;
613         } else {
614                 /*
615                  * Do we have the pathname of the program?  If so, assume we're
616                  * running an installed version of the program.  If we fail,
617                  * we don't change "datafile_dir", and thus end up using the
618                  * default.
619                  *
620                  * XXX - does NSIS put the installation directory into
621                  * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"?
622                  * If so, perhaps we should read that from the registry,
623                  * instead.
624                  */
625                 if (progfile_dir != NULL) {
626                         /*
627                          * Yes, we do; use that.
628                          */
629                         datafile_dir = progfile_dir;
630                 } else {
631                         /*
632                          * No, we don't.
633                          * Fall back on the default installation directory.
634                          */
635                         datafile_dir = "C:\\Program Files\\Wireshark\\";
636                 }
637         }
638 #else
639         if (running_in_build_directory_flag && progfile_dir != NULL) {
640                 /*
641                  * We're (probably) being run from the build directory and
642                  * weren't started with special privileges, and we were
643                  * able to determine the directory in which the program
644                  * was found, so use that.
645                  */
646                 datafile_dir = progfile_dir;
647         } else {
648                 /*
649                  * Return the directory specified when the build was
650                  * configured, prepending the run path prefix if it exists.
651                  */
652                 if (getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) {
653                         /*
654                          * The user specified a different directory for data files
655                          * and we aren't running with special privileges.
656                          * XXX - We might be able to dispense with the priv check
657                          */
658                         datafile_dir = g_strdup(getenv("WIRESHARK_DATA_DIR"));
659                 } else {
660                         datafile_dir = DATAFILE_DIR;
661                 }
662         }
663
664 #endif
665         return datafile_dir;
666 }
667
668 #ifdef HAVE_PLUGINS
669 /*
670  * Find the directory where the plugins are stored.
671  *
672  * On Windows, we use the "plugin" subdirectory of the datafile directory.
673  *
674  * On UN*X, we use the PLUGIN_DIR value supplied by the configure
675  * script, unless we think we're being run from the build directory,
676  * in which case we use the "plugin" subdirectory of the datafile directory.
677  *
678  * In both cases, we then use the subdirectory of that directory whose
679  * name is the version number.
680  *
681  * XXX - if we think we're being run from the build directory, perhaps we
682  * should have the plugin code not look in the version subdirectory
683  * of the plugin directory, but look in all of the subdirectories
684  * of the plugin directory, so it can just fetch the plugins built
685  * as part of the build process.
686  */
687 static const char *plugin_dir = NULL;
688
689 static void
690 init_plugin_dir(void)
691 {
692 #ifdef _WIN32
693         /*
694          * On Windows, the data file directory is the installation
695          * directory; the plugins are stored under it.
696          *
697          * Assume we're running the installed version of Wireshark;
698          * on Windows, the data file directory is the directory
699          * in which the Wireshark binary resides.
700          */
701         plugin_dir = g_strdup_printf("%s\\plugins\\%s", get_datafile_dir(),
702             VERSION);
703
704         /*
705          * Make sure that pathname refers to a directory.
706          */
707         if (test_for_directory(plugin_dir) != EISDIR) {
708                 /*
709                  * Either it doesn't refer to a directory or it
710                  * refers to something that doesn't exist.
711                  *
712                  * Assume that means we're running a version of
713                  * Wireshark we've built in a build directory,
714                  * in which case {datafile dir}\plugins is the
715                  * top-level plugins source directory, and use
716                  * that directory and set the "we're running in
717                  * a build directory" flag, so the plugin
718                  * scanner will check all subdirectories of that
719                  * directory for plugins.
720                  */
721                 g_free( (gpointer) plugin_dir);
722                 plugin_dir = g_strdup_printf("%s\\plugins", get_datafile_dir());
723                 running_in_build_directory_flag = TRUE;
724         }
725 #else
726         if (running_in_build_directory_flag) {
727                 /*
728                  * We're (probably) being run from the build directory and
729                  * weren't started with special privileges, so we'll use
730                  * the "plugins" subdirectory of the datafile directory
731                  * (the datafile directory is the build directory).
732                  */
733                 plugin_dir = g_strdup_printf("%s/plugins", get_datafile_dir());
734         } else {
735                 if (getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) {
736                         /*
737                          * The user specified a different directory for plugins
738                          * and we aren't running with special privileges.
739                          */
740                         plugin_dir = g_strdup(getenv("WIRESHARK_PLUGIN_DIR"));
741                 } else {
742                         plugin_dir = PLUGIN_DIR;
743                 }
744         }
745 #endif
746 }
747 #endif /* HAVE_PLUGINS */
748
749 /*
750  * Get the directory in which the plugins are stored.
751  */
752 const char *
753 get_plugin_dir(void)
754 {
755 #ifdef HAVE_PLUGINS
756         if (!plugin_dir) init_plugin_dir();
757         return plugin_dir;
758 #else
759         return NULL;
760 #endif
761 }
762
763 /*
764  * Get the flag indicating whether we're running from a build
765  * directory.
766  */
767 gboolean
768 running_in_build_directory(void)
769 {
770         return running_in_build_directory_flag;
771 }
772
773 /*
774  * Get the directory in which files that, at least on UNIX, are
775  * system files (such as "/etc/ethers") are stored; on Windows,
776  * there's no "/etc" directory, so we get them from the global
777  * configuration and data file directory.
778  */
779 const char *
780 get_systemfile_dir(void)
781 {
782 #ifdef _WIN32
783         return get_datafile_dir();
784 #else
785         return "/etc";
786 #endif
787 }
788
789 /*
790  * Name of directory, under the user's home directory, in which
791  * personal configuration files are stored.
792  */
793 #ifdef _WIN32
794 #define PF_DIR "Wireshark"
795 #else
796 /*
797  * XXX - should this be ".libepan"? For backwards-compatibility, I'll keep
798  * it ".wireshark" for now.
799  */
800 #define PF_DIR ".wireshark"
801 #endif
802
803 #ifdef _WIN32
804 /* utf8 version of getenv, needed to get win32 filename paths */
805 char *getenv_utf8(const char *varname)
806 {
807         char *envvar;
808         wchar_t *envvarw;
809         wchar_t *varnamew;
810
811         envvar = getenv(varname);
812
813         /* since GLib 2.6 we need an utf8 version of the filename */
814 #if GLIB_CHECK_VERSION(2,6,0)
815         /* using the wide char version of getenv should work under all circumstances */
816
817         /* convert given varname to utf16, needed by _wgetenv */
818         varnamew = g_utf8_to_utf16(varname, -1, NULL, NULL, NULL);
819         if (varnamew == NULL) {
820                 return envvar;
821         }
822
823         /* use wide char version of getenv */
824         envvarw = _wgetenv(varnamew);
825         g_free(varnamew);
826         if (envvarw == NULL) {
827                 return envvar;
828         }
829
830         /* convert value to utf8 */
831         envvar = g_utf16_to_utf8(envvarw, -1, NULL, NULL, NULL);
832         /* XXX - memleak */
833 #endif
834
835         return envvar;
836 }
837 #endif
838
839 void
840 set_profile_name(const gchar *profilename)
841 {
842         g_free (persconfprofile);
843
844         if (profilename && strlen(profilename) > 0 &&
845             strcmp(profilename, DEFAULT_PROFILE) != 0) {
846                 persconfprofile = g_strdup (profilename);
847         } else {
848                 /* Default Profile */
849                 persconfprofile = NULL;
850         }
851 }
852
853 const char *
854 get_profile_name(void)
855 {
856         if (persconfprofile) {
857                 return persconfprofile;
858         } else {
859                 return DEFAULT_PROFILE;
860         }
861 }
862
863 /*
864  * Get the directory in which personal configuration files reside;
865  * in UNIX-compatible systems, it's ".wireshark", under the user's home
866  * directory, and on Windows systems, it's "Wireshark", under %APPDATA%
867  * or, if %APPDATA% isn't set, it's "%USERPROFILE%\Application Data"
868  * (which is what %APPDATA% normally is on Windows 2000).
869  */
870 static const char *
871 get_persconffile_dir_no_profile(void)
872 {
873 #ifdef _WIN32
874         char *appdatadir;
875         char *userprofiledir;
876         char *u3appdatapath;
877 #else
878         const char *homedir;
879         struct passwd *pwd;
880 #endif
881
882         /* Return the cached value, if available */
883         if (persconffile_dir != NULL)
884                 return persconffile_dir;
885
886 #ifdef _WIN32
887         /*
888          * See if we are running in a U3 environment.
889          */
890         u3appdatapath = getenv_utf8("U3_APP_DATA_PATH");
891         if (u3appdatapath != NULL) {
892                 /*
893                  * We are; use the U3 application data path.
894                  */
895                 persconffile_dir = u3appdatapath;
896         } else {
897                 /*
898                  * Use %APPDATA% or %USERPROFILE%, so that configuration
899                  * files are stored in the user profile, rather than in
900                  * the home directory.  The Windows convention is to store
901                  * configuration information in the user profile, and doing
902                  * so means you can use Wireshark even if the home directory
903                  * is an inaccessible network drive.
904                  */
905                 appdatadir = getenv_utf8("APPDATA");
906                 if (appdatadir != NULL) {
907                         /*
908                          * Concatenate %APPDATA% with "\Wireshark".
909                          */
910                         persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
911                                                            appdatadir, PF_DIR);
912                 } else {
913                         /*
914                          * OK, %APPDATA% wasn't set, so use
915                          * %USERPROFILE%\Application Data.
916                          */
917                         userprofiledir = getenv_utf8("USERPROFILE");
918                         if (userprofiledir != NULL) {
919                                 persconffile_dir = g_strdup_printf(
920                                     "%s" G_DIR_SEPARATOR_S "Application Data" G_DIR_SEPARATOR_S "%s",
921                                     userprofiledir, PF_DIR);
922                         } else {
923                                 /*
924                                  * Give up and use "C:".
925                                  */
926                                 persconffile_dir = g_strdup_printf("C:" G_DIR_SEPARATOR_S "%s", PF_DIR);
927                         }
928                 }
929         }
930 #else
931         /*
932          * If $HOME is set, use that.
933          */
934         homedir = getenv("HOME");
935         if (homedir == NULL) {
936                 /*
937                  * Get their home directory from the password file.
938                  * If we can't even find a password file entry for them,
939                  * use "/tmp".
940                  */
941                 pwd = getpwuid(getuid());
942                 if (pwd != NULL) {
943                         /*
944                          * This is cached, so we don't need to worry
945                          * about allocating multiple ones of them.
946                          */
947                         homedir = g_strdup(pwd->pw_dir);
948                 } else
949                         homedir = "/tmp";
950         }
951         persconffile_dir = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", homedir, PF_DIR);
952 #endif
953
954         return persconffile_dir;
955 }
956
957 const char *
958 get_profiles_dir(void)
959 {
960         static char *profiles_dir = NULL;
961
962         g_free (profiles_dir);
963         profiles_dir = g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
964                                         G_DIR_SEPARATOR_S, PROFILES_DIR);
965
966         return profiles_dir;
967 }
968
969 static const char *
970 get_persconffile_dir(const gchar *profilename)
971 {
972         static char *persconffile_profile_dir = NULL;
973
974         g_free (persconffile_profile_dir);
975
976         if (profilename && strlen(profilename) > 0 &&
977             strcmp(profilename, DEFAULT_PROFILE) != 0) {
978           persconffile_profile_dir = g_strdup_printf ("%s%s%s", get_profiles_dir (),
979                                                       G_DIR_SEPARATOR_S, profilename);
980         } else {
981           persconffile_profile_dir = g_strdup (get_persconffile_dir_no_profile ());
982         }
983
984         return persconffile_profile_dir;
985 }
986
987 gboolean
988 profile_exists(const gchar *profilename)
989 {
990         if (test_for_directory (get_persconffile_dir (profilename)) == EISDIR) {
991                 return TRUE;
992         }
993
994         return FALSE;
995 }
996
997 static int
998 delete_directory (const char *directory, char **pf_dir_path_return)
999 {
1000         WS_DIR *dir;
1001         WS_DIRENT *file;
1002         gchar *filename;
1003         int ret = 0;
1004
1005         if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) {
1006                 while ((file = ws_dir_read_name(dir)) != NULL) {
1007                         filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S,
1008                                                     ws_dir_get_name(file));
1009                         if (test_for_directory(filename) != EISDIR) {
1010                                 ret = ws_remove(filename);
1011 #if 0
1012                         } else {
1013                                 /* The user has manually created a directory in the profile directory */
1014                                 /* I do not want to delete the directory recursively yet */
1015                                 ret = delete_directory (filename, pf_dir_path_return);
1016 #endif
1017                         }
1018                         if (ret != 0) {
1019                                 *pf_dir_path_return = filename;
1020                                 break;
1021                         }
1022                         g_free (filename);
1023                 }
1024                 ws_dir_close(dir);
1025         }
1026
1027         if (ret == 0 && (ret = ws_remove(directory)) != 0) {
1028                 *pf_dir_path_return = g_strdup (directory);
1029         }
1030
1031         return ret;
1032 }
1033
1034 int
1035 delete_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1036 {
1037         const char *profile_dir = get_persconffile_dir(profilename);
1038         int ret = 0;
1039
1040         if (test_for_directory (profile_dir) == EISDIR) {
1041                 ret = delete_directory (profile_dir, pf_dir_path_return);
1042         }
1043
1044         return ret;
1045 }
1046
1047 int
1048 rename_persconffile_profile(const char *fromname, const char *toname,
1049                             char **pf_from_dir_path_return, char **pf_to_dir_path_return)
1050 {
1051         char *from_dir = g_strdup (get_persconffile_dir(fromname));
1052         char *to_dir = g_strdup (get_persconffile_dir(toname));
1053         int ret = 0;
1054
1055         ret = ws_rename (from_dir, to_dir);
1056         if (ret != 0) {
1057                 *pf_from_dir_path_return = g_strdup (from_dir);
1058                 *pf_to_dir_path_return = g_strdup (to_dir);
1059         }
1060
1061         g_free (from_dir);
1062         g_free (to_dir);
1063
1064         return ret;
1065 }
1066
1067 /*
1068  * Create the directory that holds personal configuration files, if
1069  * necessary.  If we attempted to create it, and failed, return -1 and
1070  * set "*pf_dir_path_return" to the pathname of the directory we failed
1071  * to create (it's g_mallocated, so our caller should free it); otherwise,
1072  * return 0.
1073  */
1074 int
1075 create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1076 {
1077         const char *pf_dir_path;
1078 #ifdef _WIN32
1079         char *pf_dir_path_copy, *pf_dir_parent_path;
1080         size_t pf_dir_parent_path_len;
1081 #endif
1082         struct stat s_buf;
1083         int ret;
1084
1085         if (profilename) {
1086                 /*
1087                  * Check if profiles directory exists.
1088                  * If not then create it.
1089                  */
1090                 pf_dir_path = get_profiles_dir ();
1091                 if (ws_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
1092                         ret = ws_mkdir(pf_dir_path, 0755);
1093                         if (ret == -1) {
1094                                 *pf_dir_path_return = g_strdup(pf_dir_path);
1095                                 return ret;
1096                         }
1097                 }
1098         }
1099
1100         pf_dir_path = get_persconffile_dir(profilename);
1101         if (ws_stat(pf_dir_path, &s_buf) != 0 && errno == ENOENT) {
1102 #ifdef _WIN32
1103                 /*
1104                  * Does the parent directory of that directory
1105                  * exist?  %APPDATA% may not exist even though
1106                  * %USERPROFILE% does.
1107                  *
1108                  * We check for the existence of the directory
1109                  * by first checking whether the parent directory
1110                  * is just a drive letter and, if it's not, by
1111                  * doing a "stat()" on it.  If it's a drive letter,
1112                  * or if the "stat()" succeeds, we assume it exists.
1113                  */
1114                 pf_dir_path_copy = g_strdup(pf_dir_path);
1115                 pf_dir_parent_path = get_dirname(pf_dir_path_copy);
1116                 pf_dir_parent_path_len = strlen(pf_dir_parent_path);
1117                 if (pf_dir_parent_path_len > 0
1118                     && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
1119                     && ws_stat(pf_dir_parent_path, &s_buf) != 0) {
1120                         /*
1121                          * No, it doesn't exist - make it first.
1122                          */
1123                         ret = ws_mkdir(pf_dir_parent_path, 0755);
1124                         if (ret == -1) {
1125                                 *pf_dir_path_return = pf_dir_parent_path;
1126                                 return -1;
1127                         }
1128                 }
1129                 g_free(pf_dir_path_copy);
1130                 ret = ws_mkdir(pf_dir_path, 0755);
1131 #else
1132                 ret = ws_mkdir(pf_dir_path, 0755);
1133 #endif
1134         } else {
1135                 /*
1136                  * Something with that pathname exists; if it's not
1137                  * a directory, we'll get an error if we try to put
1138                  * something in it, so we don't fail here, we wait
1139                  * for that attempt fo fail.
1140                  */
1141                 ret = 0;
1142         }
1143         if (ret == -1)
1144                 *pf_dir_path_return = g_strdup(pf_dir_path);
1145         return ret;
1146 }
1147
1148 int
1149 create_persconffile_dir(char **pf_dir_path_return)
1150 {
1151   return create_persconffile_profile(persconfprofile, pf_dir_path_return);
1152 }
1153
1154 /*
1155  * Get the (default) directory in which personal data is stored.
1156  *
1157  * On Win32, this is the "My Documents" folder in the personal profile.
1158  * On UNIX this is simply the current directory.
1159  * On a U3 device this is "$U3_DEVICE_DOCUMENT_PATH\My Captures" folder.
1160  */
1161 /* XXX - should this and the get_home_dir() be merged? */
1162 extern char *
1163 get_persdatafile_dir(void)
1164 {
1165 #ifdef _WIN32
1166         char *u3devicedocumentpath;
1167         TCHAR tszPath[MAX_PATH];
1168         char *szPath;
1169         BOOL bRet;
1170
1171
1172         /* Return the cached value, if available */
1173         if (persdatafile_dir != NULL)
1174                 return persdatafile_dir;
1175
1176         /*
1177          * See if we are running in a U3 environment.
1178          */
1179         u3devicedocumentpath = getenv_utf8("U3_DEVICE_DOCUMENT_PATH");
1180
1181         if (u3devicedocumentpath != NULL) {
1182
1183           /* the "My Captures" sub-directory is created (if it doesn't exist)
1184                  by u3util.exe when the U3 Wireshark is first run */
1185
1186           szPath = g_strdup_printf("%s%s", u3devicedocumentpath, U3_MY_CAPTURES);
1187
1188           persdatafile_dir = szPath;
1189           return szPath;
1190
1191                 } else {
1192         /* Hint: SHGetFolderPath is not available on MSVC 6 - without Platform SDK */
1193         bRet = SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE);
1194         if(bRet == TRUE) {
1195                 szPath = utf_16to8(tszPath);
1196                 persdatafile_dir = szPath;
1197                 return szPath;
1198         } else {
1199                 return "";
1200         }
1201 }
1202 #else
1203   return "";
1204 #endif
1205 }
1206
1207 #ifdef _WIN32
1208 /*
1209  * Returns the user's home directory on Win32.
1210  */
1211 static const char *
1212 get_home_dir(void)
1213 {
1214         static const char *home = NULL;
1215         char *homedrive, *homepath;
1216         char *homestring;
1217         char *lastsep;
1218
1219         /* Return the cached value, if available */
1220         if (home)
1221                 return home;
1222
1223         /*
1224          * XXX - should we use USERPROFILE anywhere in this process?
1225          * Is there a chance that it might be set but one or more of
1226          * HOMEDRIVE or HOMEPATH isn't set?
1227          */
1228         homedrive = getenv_utf8("HOMEDRIVE");
1229         if (homedrive != NULL) {
1230                 homepath = getenv_utf8("HOMEPATH");
1231                 if (homepath != NULL) {
1232                         /*
1233                          * This is cached, so we don't need to worry about
1234                          * allocating multiple ones of them.
1235                          */
1236                         homestring = g_strdup_printf("%s%s", homedrive, homepath);
1237
1238                         /*
1239                          * Trim off any trailing slash or backslash.
1240                          */
1241                         lastsep = find_last_pathname_separator(homestring);
1242                         if (lastsep != NULL && *(lastsep + 1) == '\0') {
1243                                 /*
1244                                  * Last separator is the last character
1245                                  * in the string.  Nuke it.
1246                                  */
1247                                 *lastsep = '\0';
1248                         }
1249                         home = homestring;
1250                 } else
1251                         home = homedrive;
1252         } else {
1253                 /*
1254                  * Give up and use C:.
1255                  */
1256                 home = "C:";
1257         }
1258
1259         return home;
1260 }
1261 #endif
1262
1263 /*
1264  * Construct the path name of a personal configuration file, given the
1265  * file name.
1266  *
1267  * On Win32, if "for_writing" is FALSE, we check whether the file exists
1268  * and, if not, construct a path name relative to the ".wireshark"
1269  * subdirectory of the user's home directory, and check whether that
1270  * exists; if it does, we return that, so that configuration files
1271  * from earlier versions can be read.
1272  *
1273  * The returned file name was g_malloc()'d so it must be g_free()d when the
1274  * caller is done with it.
1275  */
1276 char *
1277 get_persconffile_path(const char *filename, gboolean from_profile, gboolean for_writing
1278 #ifndef _WIN32
1279         _U_
1280 #endif
1281 )
1282 {
1283         char *path;
1284 #ifdef _WIN32
1285         struct stat s_buf;
1286         char *old_path;
1287 #endif
1288
1289         if (from_profile) {
1290           path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1291                                  get_persconffile_dir(persconfprofile), filename);
1292         } else {
1293           path = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s",
1294                                  get_persconffile_dir(NULL), filename);
1295         }
1296 #ifdef _WIN32
1297         if (!for_writing) {
1298                 if (ws_stat(path, &s_buf) != 0 && errno == ENOENT) {
1299                         /*
1300                          * OK, it's not in the personal configuration file
1301                          * directory; is it in the ".wireshark" subdirectory
1302                          * of their home directory?
1303                          */
1304                         old_path = g_strdup_printf(
1305                             "%s" G_DIR_SEPARATOR_S ".wireshark" G_DIR_SEPARATOR_S "%s",
1306                             get_home_dir(), filename);
1307                         if (ws_stat(old_path, &s_buf) == 0) {
1308                                 /*
1309                                  * OK, it exists; return it instead.
1310                                  */
1311                                 g_free(path);
1312                                 path = old_path;
1313                         }
1314                 }
1315         }
1316 #endif
1317
1318         return path;
1319 }
1320
1321 /*
1322  * process command line option belonging to the filesystem settings
1323  * (move this e.g. to main.c and have set_persconffile_dir() instead in this file?)
1324  */
1325 int
1326 filesystem_opt(int opt _U_, const char *optstr)
1327 {
1328         gchar *p, *colonp;
1329
1330         colonp = strchr(optstr, ':');
1331         if (colonp == NULL) {
1332                 return 1;
1333         }
1334
1335         p = colonp;
1336         *p++ = '\0';
1337
1338         /*
1339         * Skip over any white space (there probably won't be any, but
1340         * as we allow it in the preferences file, we might as well
1341         * allow it here).
1342         */
1343         while (isspace((guchar)*p))
1344                 p++;
1345         if (*p == '\0') {
1346                 /*
1347                  * Put the colon back, so if our caller uses, in an
1348                  * error message, the string they passed us, the message
1349                  * looks correct.
1350                  */
1351                 *colonp = ':';
1352                 return 1;
1353         }
1354
1355         /* directory should be existing */
1356         /* XXX - is this a requirement? */
1357         if(test_for_directory(p) != EISDIR) {
1358                 /*
1359                  * Put the colon back, so if our caller uses, in an
1360                  * error message, the string they passed us, the message
1361                  * looks correct.
1362                  */
1363                 *colonp = ':';
1364                 return 1;
1365         }
1366
1367         if (strcmp(optstr,"persconf") == 0) {
1368                 persconffile_dir = p;
1369         } else if (strcmp(optstr,"persdata") == 0) {
1370                 persdatafile_dir = p;
1371                 /* XXX - might need to add the temp file path */
1372         } else {
1373                 return 1;
1374         }
1375         *colonp = ':'; /* put the colon back */
1376         return 0;
1377 }
1378
1379 /*
1380  * Construct the path name of a global configuration file, given the
1381  * file name.
1382  *
1383  * The returned file name was g_malloc()'d so it must be g_free()d when the
1384  * caller is done with it.
1385  */
1386 char *
1387 get_datafile_path(const char *filename)
1388 {
1389
1390         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", get_datafile_dir(),
1391                 filename);
1392 }
1393
1394 /* Delete a file */
1395 gboolean
1396 deletefile(const char *path)
1397 {
1398         return ws_unlink(path) == 0;
1399 }
1400
1401 /*
1402  * Construct and return the path name of a file in the
1403  * appropriate temporary file directory.
1404  */
1405 char *get_tempfile_path(const char *filename)
1406 {
1407         return g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", g_get_tmp_dir(), filename);
1408 }
1409
1410 /*
1411  * Return an error message for UNIX-style errno indications on open or
1412  * create operations.
1413  */
1414 const char *
1415 file_open_error_message(int err, gboolean for_writing)
1416 {
1417         const char *errmsg;
1418         static char errmsg_errno[1024+1];
1419
1420         switch (err) {
1421
1422         case ENOENT:
1423                 if (for_writing)
1424                         errmsg = "The path to the file \"%s\" doesn't exist.";
1425                 else
1426                         errmsg = "The file \"%s\" doesn't exist.";
1427                 break;
1428
1429         case EACCES:
1430                 if (for_writing)
1431                         errmsg = "You don't have permission to create or write to the file \"%s\".";
1432                 else
1433                         errmsg = "You don't have permission to read the file \"%s\".";
1434                 break;
1435
1436         case EISDIR:
1437                 errmsg = "\"%s\" is a directory (folder), not a file.";
1438                 break;
1439
1440         case ENOSPC:
1441                 errmsg = "The file \"%s\" could not be created because there is no space left on the file system.";
1442                 break;
1443
1444 #ifdef EDQUOT
1445         case EDQUOT:
1446                 errmsg = "The file \"%s\" could not be created because you are too close to, or over, your disk quota.";
1447                 break;
1448 #endif
1449
1450         case EINVAL:
1451                 errmsg = "The file \"%s\" could not be created because an invalid filename was specified.";
1452                 break;
1453
1454         default:
1455                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1456                                 "The file \"%%s\" could not be %s: %s.",
1457                                 for_writing ? "created" : "opened",
1458                                 strerror(err));
1459                 errmsg = errmsg_errno;
1460                 break;
1461         }
1462         return errmsg;
1463 }
1464
1465 /*
1466  * Return an error message for UNIX-style errno indications on write
1467  * operations.
1468  */
1469 const char *
1470 file_write_error_message(int err)
1471 {
1472         const char *errmsg;
1473         static char errmsg_errno[1024+1];
1474
1475         switch (err) {
1476
1477         case ENOSPC:
1478                 errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
1479                 break;
1480
1481 #ifdef EDQUOT
1482         case EDQUOT:
1483                 errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
1484                 break;
1485 #endif
1486
1487         default:
1488                 g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1489                     "An error occurred while writing to the file \"%%s\": %s.",
1490                     strerror(err));
1491                 errmsg = errmsg_errno;
1492                 break;
1493         }
1494         return errmsg;
1495 }
1496
1497
1498 gboolean
1499 file_exists(const char *fname)
1500 {
1501         struct stat   file_stat;
1502
1503 #ifdef _WIN32
1504         /*
1505          * This is a bit tricky on win32. The st_ino field is documented as:
1506          * "The inode, and therefore st_ino, has no meaning in the FAT, ..."
1507          * but it *is* set to zero if stat() returns without an error,
1508          * so this is working, but maybe not quite the way expected. ULFL
1509          */
1510         file_stat.st_ino = 1;   /* this will make things work if an error occured */
1511         ws_stat(fname, &file_stat);
1512         if (file_stat.st_ino == 0) {
1513                 return TRUE;
1514         } else {
1515                 return FALSE;
1516         }
1517 #else
1518         if (ws_stat(fname, &file_stat) != 0 && errno == ENOENT) {
1519                 return FALSE;
1520         } else {
1521                 return TRUE;
1522         }
1523 #endif
1524 }
1525
1526 /*
1527  * Check that the from file is not the same as to file
1528  * We do it here so we catch all cases ...
1529  * Unfortunately, the file requester gives us an absolute file
1530  * name and the read file name may be relative (if supplied on
1531  * the command line), so we can't just compare paths. From Joerg Mayer.
1532  */
1533 gboolean
1534 files_identical(const char *fname1, const char *fname2)
1535 {
1536         /* Two different implementations, because:
1537          *
1538          * - _fullpath is not available on UN*X, so we can't get full
1539          *   paths and compare them (which wouldn't work with hard links
1540          *   in any case);
1541          *
1542          * - st_ino isn't filled in with a meaningful value on Windows.
1543          */
1544 #ifdef _WIN32
1545         char full1[MAX_PATH], full2[MAX_PATH];
1546
1547         /*
1548          * Get the absolute full paths of the file and compare them.
1549          * That won't work if you have hard links, but those aren't
1550          * much used on Windows, even though NTFS supports them.
1551          *
1552          * XXX - will _fullpath work with UNC?
1553          */
1554         if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
1555                 return FALSE;
1556         }
1557
1558         if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
1559                 return FALSE;
1560         }
1561
1562         if(strcmp(full1, full2) == 0) {
1563                 return TRUE;
1564         } else {
1565                 return FALSE;
1566         }
1567 #else
1568         struct stat   filestat1, filestat2;
1569
1570         /*
1571          * Compare st_dev and st_ino.
1572          */
1573         if (ws_stat(fname1, &filestat1) == -1)
1574                 return FALSE;   /* can't get info about the first file */
1575         if (ws_stat(fname2, &filestat2) == -1)
1576                 return FALSE;   /* can't get info about the second file */
1577         return (filestat1.st_dev == filestat2.st_dev &&
1578                 filestat1.st_ino == filestat2.st_ino);
1579 #endif
1580 }
1581
1582 /*
1583  * Copy a file in binary mode, for those operating systems that care about
1584  * such things.  This should be OK for all files, even text files, as
1585  * we'll copy the raw bytes, and we don't look at the bytes as we copy
1586  * them.
1587  *
1588  * Returns TRUE on success, FALSE on failure. If a failure, it also
1589  * displays a simple dialog window with the error message.
1590  */
1591 gboolean
1592 copy_file_binary_mode(const char *from_filename, const char *to_filename)
1593 {
1594   int           from_fd, to_fd, nread, nwritten, err;
1595   guint8        pd[65536];
1596
1597   /* Copy the raw bytes of the file. */
1598   from_fd = ws_open(from_filename, O_RDONLY | O_BINARY, 0000 /* no creation so don't matter */);
1599   if (from_fd < 0) {
1600     report_open_failure(from_filename, errno, FALSE);
1601     goto done;
1602   }
1603
1604   /* Use open() instead of creat() so that we can pass the O_BINARY
1605      flag, which is relevant on Win32; it appears that "creat()"
1606      may open the file in text mode, not binary mode, but we want
1607      to copy the raw bytes of the file, so we need the output file
1608      to be open in binary mode. */
1609   to_fd = ws_open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
1610   if (to_fd < 0) {
1611     report_open_failure(to_filename, errno, TRUE);
1612     ws_close(from_fd);
1613     goto done;
1614   }
1615
1616   while ((nread = ws_read(from_fd, pd, sizeof pd)) > 0) {
1617     nwritten = ws_write(to_fd, pd, nread);
1618     if (nwritten < nread) {
1619       if (nwritten < 0)
1620         err = errno;
1621       else
1622         err = WTAP_ERR_SHORT_WRITE;
1623       report_write_failure(to_filename, err);
1624       ws_close(from_fd);
1625       ws_close(to_fd);
1626       goto done;
1627     }
1628   }
1629   if (nread < 0) {
1630     err = errno;
1631     report_read_failure(from_filename, err);
1632     ws_close(from_fd);
1633     ws_close(to_fd);
1634     goto done;
1635   }
1636   ws_close(from_fd);
1637   if (ws_close(to_fd) < 0) {
1638     report_write_failure(to_filename, errno);
1639     goto done;
1640   }
1641
1642   return TRUE;
1643
1644 done:
1645   return FALSE;
1646 }
1647
1648 /*
1649  * Editor modelines
1650  *
1651  * Local Variables:
1652  * c-basic-offset: 4
1653  * tab-width: 4
1654  * indent-tabs-mode: t
1655  * End:
1656  *
1657  * ex: set shiftwidth=4 tabstop=4 noexpandtab
1658  * :indentSize=4:tabSize=4:noTabs=false:
1659  */