1 /* filesystem.c
2  * Filesystem utility routines
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * SPDX-License-Identifier: GPL-2.0-or-later
9  */
10 
11 #include <config.h>
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 
18 #include <glib.h>
19 
20 #ifdef _WIN32
21 #include <windows.h>
22 #include <tchar.h>
23 #include <shlobj.h>
24 #include <wsutil/unicode-utils.h>
25 #else /* _WIN32 */
26 #ifdef __APPLE__
27 #include <mach-o/dyld.h>
28 #endif
29 #ifdef __linux__
30 #include <sys/utsname.h>
31 #endif
32 #ifdef __FreeBSD__
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35 #endif
36 #ifdef HAVE_DLGET
37 #include <dlfcn.h>
38 #endif
39 #include <pwd.h>
40 #endif /* _WIN32 */
41 
42 #include "filesystem.h"
43 #include <wsutil/report_message.h>
44 #include <wsutil/privileges.h>
45 #include <wsutil/file_util.h>
46 #include <wsutil/utf8_entities.h>
47 #include <wsutil/ws_assert.h>
48 
49 #include <wiretap/wtap.h>   /* for WTAP_ERR_SHORT_WRITE */
50 
51 #define PROFILES_DIR    "profiles"
52 #define PLUGINS_DIR_NAME    "plugins"
53 #define PROFILES_INFO_NAME  "profile_files.txt"
54 
55 #define ENV_CONFIG_PATH_VAR  "WIRESHARK_CONFIG_DIR"
56 
57 char *persconffile_dir = NULL;
58 char *datafile_dir = NULL;
59 char *persdatafile_dir = NULL;
60 char *persconfprofile = NULL;
61 
62 static gboolean do_store_persconffiles = FALSE;
63 static GHashTable *profile_files = NULL;
64 
65 /*
66  * Given a pathname, return a pointer to the last pathname separator
67  * character in the pathname, or NULL if the pathname contains no
68  * separators.
69  */
70 char *
find_last_pathname_separator(const char * path)71 find_last_pathname_separator(const char *path)
72 {
73     char *separator;
74 
75 #ifdef _WIN32
76     char c;
77 
78     /*
79      * We have to scan for '\' or '/'.
80      * Get to the end of the string.
81      */
82     separator = strchr(path, '\0');     /* points to ending '\0' */
83     while (separator > path) {
84         c = *--separator;
85         if (c == '\\' || c == '/')
86             return separator;   /* found it */
87     }
88 
89     /*
90      * OK, we didn't find any, so no directories - but there might
91      * be a drive letter....
92      */
93     return strchr(path, ':');
94 #else
95     separator = strrchr(path, '/');
96     return separator;
97 #endif
98 }
99 
100 /*
101  * Given a pathname, return the last component.
102  */
103 const char *
get_basename(const char * path)104 get_basename(const char *path)
105 {
106     const char *filename;
107 
108     ws_assert(path != NULL);
109     filename = find_last_pathname_separator(path);
110     if (filename == NULL) {
111         /*
112          * There're no directories, drive letters, etc. in the
113          * name; the pathname *is* the file name.
114          */
115         filename = path;
116     } else {
117         /*
118          * Skip past the pathname or drive letter separator.
119          */
120         filename++;
121     }
122     return filename;
123 }
124 
125 /*
126  * Given a pathname, return a string containing everything but the
127  * last component.  NOTE: this overwrites the pathname handed into
128  * it....
129  */
130 char *
get_dirname(char * path)131 get_dirname(char *path)
132 {
133     char *separator;
134 
135     ws_assert(path != NULL);
136     separator = find_last_pathname_separator(path);
137     if (separator == NULL) {
138         /*
139          * There're no directories, drive letters, etc. in the
140          * name; there is no directory path to return.
141          */
142         return NULL;
143     }
144 
145     /*
146      * Get rid of the last pathname separator and the final file
147      * name following it.
148      */
149     *separator = '\0';
150 
151     /*
152      * "path" now contains the pathname of the directory containing
153      * the file/directory to which it referred.
154      */
155     return path;
156 }
157 
158 /*
159  * Given a pathname, return:
160  *
161  *  the errno, if an attempt to "stat()" the file fails;
162  *
163  *  EISDIR, if the attempt succeeded and the file turned out
164  *  to be a directory;
165  *
166  *  0, if the attempt succeeded and the file turned out not
167  *  to be a directory.
168  */
169 
170 int
test_for_directory(const char * path)171 test_for_directory(const char *path)
172 {
173     ws_statb64 statb;
174 
175     if (ws_stat64(path, &statb) < 0)
176         return errno;
177 
178     if (S_ISDIR(statb.st_mode))
179         return EISDIR;
180     else
181         return 0;
182 }
183 
184 int
test_for_fifo(const char * path)185 test_for_fifo(const char *path)
186 {
187     ws_statb64 statb;
188 
189     if (ws_stat64(path, &statb) < 0)
190         return errno;
191 
192     if (S_ISFIFO(statb.st_mode))
193         return ESPIPE;
194     else
195         return 0;
196 }
197 
198 /*
199  * Directory from which the executable came.
200  */
201 static char *progfile_dir;
202 
203 #ifdef __APPLE__
204 /*
205  * Directory of the application bundle in which we're contained,
206  * if we're contained in an application bundle.  Otherwise, NULL.
207  *
208  * Note: Table 2-5 "Subdirectories of the Contents directory" of
209  *
210  *    https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1
211  *
212  * says that the "Frameworks" directory
213  *
214  *    Contains any private shared libraries and frameworks used by the
215  *    executable.  The frameworks in this directory are revision-locked
216  *    to the application and cannot be superseded by any other, even
217  *    newer, versions that may be available to the operating system.  In
218  *    other words, the frameworks included in this directory take precedence
219  *    over any other similarly named frameworks found in other parts of
220  *    the operating system.  For information on how to add private
221  *    frameworks to your application bundle, see Framework Programming Guide.
222  *
223  * so if we were to ship with any frameworks (e.g. Qt) we should
224  * perhaps put them in a Frameworks directory rather than under
225  * Resources.
226  *
227  * It also says that the "PlugIns" directory
228  *
229  *    Contains loadable bundles that extend the basic features of your
230  *    application. You use this directory to include code modules that
231  *    must be loaded into your applicationbs process space in order to
232  *    be used. You would not use this directory to store standalone
233  *    executables.
234  *
235  * Our plugins are just raw .so/.dylib files; I don't know whether by
236  * "bundles" they mean application bundles (i.e., directory hierarchies)
237  * or just "bundles" in the Mach-O sense (which are an image type that
238  * can be loaded with dlopen() but not linked as libraries; our plugins
239  * are, I think, built as dylibs and can be loaded either way).
240  *
241  * And it says that the "SharedSupport" directory
242  *
243  *    Contains additional non-critical resources that do not impact the
244  *    ability of the application to run. You might use this directory to
245  *    include things like document templates, clip art, and tutorials
246  *    that your application expects to be present but that do not affect
247  *    the ability of your application to run.
248  *
249  * I don't think I'd put the files that currently go under Resources/share
250  * into that category; they're not, for example, sample Lua scripts that
251  * don't actually get run by Wireshark, they're configuration/data files
252  * for Wireshark whose absence might not prevent Wireshark from running
253  * but that would affect how it behaves when run.
254  */
255 static char *appbundle_dir;
256 #endif
257 
258 /*
259  * TRUE if we're running from the build directory and we aren't running
260  * with special privileges.
261  */
262 static gboolean running_in_build_directory_flag = FALSE;
263 
264 #ifndef _WIN32
265 /*
266  * Get the pathname of the executable using various platform-
267  * dependent mechanisms for various UN*Xes.
268  *
269  * These calls all should return something independent of the argv[0]
270  * passed to the program, so it shouldn't be fooled by an argv[0]
271  * that doesn't match the executable path.
272  *
273  * We don't use dladdr() because:
274  *
275  *   not all UN*Xes necessarily have dladdr();
276  *
277  *   those that do have it don't necessarily have dladdr(main)
278  *   return information about the executable image;
279  *
280  *   those that do have a dladdr() where dladdr(main) returns
281  *   information about the executable image don't necessarily
282  *   have a mechanism by which the executable image can get
283  *   its own path from the kernel (either by a call or by it
284  *   being handed to it along with argv[] and the environment),
285  *   so they just fall back on getting it from argv[0], which we
286  *   already have code to do;
287  *
288  *   those that do have such a mechanism don't necessarily use
289  *   it in dladdr(), and, instead, just fall back on getting it
290  *   from argv[0];
291  *
292  * so the only places where it's worth bothering to use dladdr()
293  * are platforms where dladdr(main) return information about the
294  * executable image by getting it from the kernel rather than
295  * by looking at argv[0], and where we can't get at that information
296  * ourselves, and we haven't seen any indication that there are any
297  * such platforms.
298  *
299  * In particular, some dynamic linkers supply a dladdr() such that
300  * dladdr(main) just returns something derived from argv[0], so
301  * just using dladdr(main) is the wrong thing to do if there's
302  * another mechanism that can get you a more reliable version of
303  * the executable path.
304  *
305  * So, on platforms where we know of a mechanism to get that path
306  * (where getting that path doesn't involve argv[0], which is not
307  * guaranteed to reflect the path to the binary), this routine
308  * attempsts to use that platform's mechanism.  On other platforms,
309  * it just returns NULL.
310  *
311  * This is not guaranteed to return an absolute path; if it doesn't,
312  * our caller must prepend the current directory if it's a path.
313  *
314  * This is not guaranteed to return the "real path"; it might return
315  * something with symbolic links in the path.  Our caller must
316  * use realpath() if they want the real thing, but that's also true of
317  * something obtained by looking at argv[0].
318  */
319 #define xx_free free  /* hack so checkAPIs doesn't complain */
320 static const char *
get_executable_path(void)321 get_executable_path(void)
322 {
323 #if defined(__APPLE__)
324     static char *executable_path;
325     uint32_t path_buf_size;
326 
327     if (executable_path) {
328         return executable_path;
329     }
330 
331     path_buf_size = PATH_MAX;
332     executable_path = (char *)g_malloc(path_buf_size);
333     if (_NSGetExecutablePath(executable_path, &path_buf_size) == -1) {
334         executable_path = (char *)g_realloc(executable_path, path_buf_size);
335         if (_NSGetExecutablePath(executable_path, &path_buf_size) == -1)
336             return NULL;
337     }
338     /*
339      * Resolve our path so that it's possible to symlink the executables
340      * in our application bundle.
341      */
342     char *rp_execpath = realpath(executable_path, NULL);
343     if (rp_execpath) {
344         g_free(executable_path);
345         executable_path = g_strdup(rp_execpath);
346         xx_free(rp_execpath);
347     }
348     return executable_path;
349 #elif defined(__linux__)
350     /*
351      * In older versions of GNU libc's dynamic linker, as used on Linux,
352      * dladdr(main) supplies a path based on argv[0], so we use
353      * /proc/self/exe instead; there are Linux distributions with
354      * kernels that support /proc/self/exe and those older versions
355      * of the dynamic linker, and this will get a better answer on
356      * those versions.
357      *
358      * It only works on Linux 2.2 or later, so we just give up on
359      * earlier versions.
360      *
361      * XXX - are there OS versions that support "exe" but not "self"?
362      */
363     struct utsname name;
364     static char executable_path[PATH_MAX + 1];
365     ssize_t r;
366 
367     if (uname(&name) == -1)
368         return NULL;
369     if (strncmp(name.release, "1.", 2) == 0)
370         return NULL; /* Linux 1.x */
371     if (strcmp(name.release, "2.0") == 0 ||
372         strncmp(name.release, "2.0.", 4) == 0 ||
373         strcmp(name.release, "2.1") == 0 ||
374         strncmp(name.release, "2.1.", 4) == 0)
375         return NULL; /* Linux 2.0.x or 2.1.x */
376     if ((r = readlink("/proc/self/exe", executable_path, PATH_MAX)) == -1)
377         return NULL;
378     executable_path[r] = '\0';
379     return executable_path;
380 #elif defined(__FreeBSD__) && defined(KERN_PROC_PATHNAME)
381     /*
382      * In older versions of FreeBSD's dynamic linker, dladdr(main)
383      * supplies a path based on argv[0], so we use the KERN_PROC_PATHNAME
384      * sysctl instead; there are, I think, versions of FreeBSD
385      * that support the sysctl that have and those older versions
386      * of the dynamic linker, and this will get a better answer on
387      * those versions.
388      */
389     int mib[4];
390     char *executable_path;
391     size_t path_buf_size;
392 
393     mib[0] = CTL_KERN;
394     mib[1] = KERN_PROC;
395     mib[2] = KERN_PROC_PATHNAME;
396     mib[3] = -1;
397     path_buf_size = PATH_MAX;
398     executable_path = (char *)g_malloc(path_buf_size);
399     if (sysctl(mib, 4, executable_path, &path_buf_size, NULL, 0) == -1) {
400         if (errno != ENOMEM)
401             return NULL;
402         executable_path = (char *)g_realloc(executable_path, path_buf_size);
403         if (sysctl(mib, 4, executable_path, &path_buf_size, NULL, 0) == -1)
404             return NULL;
405     }
406     return executable_path;
407 #elif defined(__NetBSD__)
408     /*
409      * In all versions of NetBSD's dynamic linker as of 2013-08-12,
410      * dladdr(main) supplies a path based on argv[0], so we use
411      * /proc/curproc/exe instead.
412      *
413      * XXX - are there OS versions that support "exe" but not "curproc"
414      * or "self"?  Are there any that support "self" but not "curproc"?
415      */
416     static char executable_path[PATH_MAX + 1];
417     ssize_t r;
418 
419     if ((r = readlink("/proc/curproc/exe", executable_path, PATH_MAX)) == -1)
420         return NULL;
421     executable_path[r] = '\0';
422     return executable_path;
423 #elif defined(__DragonFly__)
424     /*
425      * In older versions of DragonFly BSD's dynamic linker, dladdr(main)
426      * supplies a path based on argv[0], so we use /proc/curproc/file
427      * instead; it appears to be supported by all versions of DragonFly
428      * BSD.
429      */
430     static char executable_path[PATH_MAX + 1];
431     ssize_t r;
432 
433     if ((r = readlink("/proc/curproc/file", executable_path, PATH_MAX)) == -1)
434         return NULL;
435     executable_path[r] = '\0';
436     return executable_path;
437 #elif defined(HAVE_GETEXECNAME)
438     /*
439      * Solaris, with getexecname().
440      * It appears that getexecname() dates back to at least Solaris 8,
441      * but /proc/{pid}/path is first documented in the Solaris 10 documentation,
442      * so we use getexecname() if available, rather than /proc/self/path/a.out
443      * (which isn't documented, but appears to be a symlink to the
444      * executable image file).
445      */
446     return getexecname();
447 #elif defined(HAVE_DLGET)
448     /*
449      * HP-UX 11, with dlget(); use dlget() and dlgetname().
450      * See
451      *
452      *  https://web.archive.org/web/20081025174755/http://h21007.www2.hp.com/portal/site/dspp/menuitem.863c3e4cbcdc3f3515b49c108973a801?ciid=88086d6e1de021106d6e1de02110275d6e10RCRD#two
453      */
454     struct load_module_desc desc;
455 
456     if (dlget(-2, &desc, sizeof(desc)) != NULL)
457         return dlgetname(&desc, sizeof(desc), NULL, NULL, NULL);
458     else
459         return NULL;
460 #else
461     /* Fill in your favorite UN*X's code here, if there is something */
462     return NULL;
463 #endif
464 }
465 #endif /* _WIN32 */
466 
467 /*
468  * Get the pathname of the directory from which the executable came,
469  * and save it for future use.  Returns NULL on success, and a
470  * g_mallocated string containing an error on failure.
471  */
472 char *
init_progfile_dir(const char * arg0 _U_)473 init_progfile_dir(
474 #ifdef _WIN32
475     const char* arg0 _U_
476 #else
477     const char* arg0
478 #endif
479 )
480 {
481 #ifdef _WIN32
482     TCHAR prog_pathname_w[_MAX_PATH+2];
483     char *prog_pathname;
484     DWORD error;
485     TCHAR *msg_w;
486     guchar *msg;
487     size_t msglen;
488 
489     /*
490      * Attempt to get the full pathname of the currently running
491      * program.
492      */
493     if (GetModuleFileName(NULL, prog_pathname_w, G_N_ELEMENTS(prog_pathname_w)) != 0 && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
494         /*
495          * XXX - Should we use g_utf16_to_utf8()?
496          */
497         prog_pathname = utf_16to8(prog_pathname_w);
498         /*
499          * We got it; strip off the last component, which would be
500          * the file name of the executable, giving us the pathname
501          * of the directory where the executable resides.
502          */
503         progfile_dir = g_path_get_dirname(prog_pathname);
504         if (progfile_dir != NULL) {
505             return NULL;    /* we succeeded */
506         } else {
507             /*
508              * OK, no. What do we do now?
509              */
510             return g_strdup_printf("No \\ in executable pathname \"%s\"",
511                 prog_pathname);
512         }
513     } else {
514         /*
515          * Oh, well.  Return an indication of the error.
516          */
517         error = GetLastError();
518         if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
519             NULL, error, 0, (LPTSTR) &msg_w, 0, NULL) == 0) {
520             /*
521              * Gak.  We can't format the message.
522              */
523             return g_strdup_printf("GetModuleFileName failed: %u (FormatMessage failed: %u)",
524                 error, GetLastError());
525         }
526         msg = utf_16to8(msg_w);
527         LocalFree(msg_w);
528         /*
529          * "FormatMessage()" "helpfully" sticks CR/LF at the
530          * end of the message.  Get rid of it.
531          */
532         msglen = strlen(msg);
533         if (msglen >= 2) {
534             msg[msglen - 1] = '\0';
535             msg[msglen - 2] = '\0';
536         }
537         return g_strdup_printf("GetModuleFileName failed: %s (%u)",
538             msg, error);
539     }
540 #else
541     const char *execname;
542     char *prog_pathname;
543     char *curdir;
544     long path_max;
545     const char *pathstr;
546     const char *path_start, *path_end;
547     size_t path_component_len, path_len;
548     char *retstr;
549     char *path;
550     char *dir_end;
551 
552     /*
553      * Check whether WIRESHARK_RUN_FROM_BUILD_DIRECTORY is set in the
554      * environment; if so, set running_in_build_directory_flag if we
555      * weren't started with special privileges.  (If we were started
556      * with special privileges, it's not safe to allow the user to point
557      * us to some other directory; running_in_build_directory_flag, when
558      * set, causes us to look for plugins and the like in the build
559      * directory.)
560      */
561     if (g_getenv("WIRESHARK_RUN_FROM_BUILD_DIRECTORY") != NULL
562         && !started_with_special_privs())
563         running_in_build_directory_flag = TRUE;
564 
565     execname = get_executable_path();
566     if (execname == NULL) {
567         /*
568          * OK, guess based on argv[0].
569          */
570         execname = arg0;
571     }
572 
573     /*
574      * Try to figure out the directory in which the currently running
575      * program resides, given something purporting to be the executable
576      * name (from an OS mechanism or from the argv[0] it was started with).
577      * That might be the absolute path of the program, or a path relative
578      * to the current directory of the process that started it, or
579      * just a name for the program if it was started from the command
580      * line and was searched for in $PATH.  It's not guaranteed to be
581      * any of those, however, so there are no guarantees....
582      */
583     if (execname[0] == '/') {
584         /*
585          * It's an absolute path.
586          */
587         prog_pathname = g_strdup(execname);
588     } else if (strchr(execname, '/') != NULL) {
589         /*
590          * It's a relative path, with a directory in it.
591          * Get the current directory, and combine it
592          * with that directory.
593          */
594         path_max = pathconf(".", _PC_PATH_MAX);
595         if (path_max == -1) {
596             /*
597              * We have no idea how big a buffer to
598              * allocate for the current directory.
599              */
600             return g_strdup_printf("pathconf failed: %s\n",
601                 g_strerror(errno));
602         }
603         curdir = (char *)g_malloc(path_max);
604         if (getcwd(curdir, path_max) == NULL) {
605             /*
606              * It failed - give up, and just stick
607              * with DATA_DIR.
608              */
609             g_free(curdir);
610             return g_strdup_printf("getcwd failed: %s\n",
611                 g_strerror(errno));
612         }
613         path = g_strdup_printf("%s/%s", curdir, execname);
614         g_free(curdir);
615         prog_pathname = path;
616     } else {
617         /*
618          * It's just a file name.
619          * Search the path for a file with that name
620          * that's executable.
621          */
622         prog_pathname = NULL;   /* haven't found it yet */
623         pathstr = g_getenv("PATH");
624         path_start = pathstr;
625         if (path_start != NULL) {
626             while (*path_start != '\0') {
627                 path_end = strchr(path_start, ':');
628                 if (path_end == NULL)
629                     path_end = path_start + strlen(path_start);
630                 path_component_len = path_end - path_start;
631                 path_len = path_component_len + 1
632                     + strlen(execname) + 1;
633                 path = (char *)g_malloc(path_len);
634                 memcpy(path, path_start, path_component_len);
635                 path[path_component_len] = '\0';
636                 (void) g_strlcat(path, "/", path_len);
637                 (void) g_strlcat(path, execname, path_len);
638                 if (access(path, X_OK) == 0) {
639                     /*
640                      * Found it!
641                      */
642                     prog_pathname = path;
643                     break;
644                 }
645 
646                 /*
647                  * That's not it.  If there are more
648                  * path components to test, try them.
649                  */
650                 if (*path_end == ':')
651                     path_end++;
652                 path_start = path_end;
653                 g_free(path);
654             }
655             if (prog_pathname == NULL) {
656                 /*
657                  * Program not found in path.
658                  */
659                 return g_strdup_printf("\"%s\" not found in \"%s\"",
660                     execname, pathstr);
661             }
662         } else {
663             /*
664              * PATH isn't set.
665              * XXX - should we pick a default?
666              */
667             return g_strdup("PATH isn't set");
668         }
669     }
670 
671     /*
672      * OK, we have what we think is the pathname
673      * of the program.
674      *
675      * First, find the last "/" in the directory,
676      * as that marks the end of the directory pathname.
677      */
678     dir_end = strrchr(prog_pathname, '/');
679     if (dir_end != NULL) {
680         /*
681          * Found it.  Strip off the last component,
682          * as that's the path of the program.
683          */
684         *dir_end = '\0';
685 
686         /*
687          * Is there a "/run" at the end?
688          */
689         dir_end = strrchr(prog_pathname, '/');
690         if (dir_end != NULL) {
691             if (!started_with_special_privs()) {
692                 /*
693                  * Check for the CMake output directory. As people may name
694                  * their directories "run" (really?), also check for the
695                  * CMakeCache.txt file before assuming a CMake output dir.
696                  */
697                 if (strcmp(dir_end, "/run") == 0) {
698                     gchar *cmake_file;
699                     cmake_file = g_strdup_printf("%.*s/CMakeCache.txt",
700                                                  (int)(dir_end - prog_pathname),
701                                                  prog_pathname);
702                     if (file_exists(cmake_file))
703                         running_in_build_directory_flag = TRUE;
704                     g_free(cmake_file);
705                 }
706 #ifdef __APPLE__
707                 {
708                     /*
709                      * Scan up the path looking for a component
710                      * named "Contents".  If we find it, we assume
711                      * we're in a bundle, and that the top-level
712                      * directory of the bundle is the one containing
713                      * "Contents".
714                      *
715                      * Not all executables are in the Contents/MacOS
716                      * directory, so we can't just check for those
717                      * in the path and strip them off.
718                      *
719                      * XXX - should we assume that it's either
720                      * Contents/MacOS or Resources/bin?
721                      */
722                     char *component_end, *p;
723 
724                     component_end = strchr(prog_pathname, '\0');
725                     p = component_end;
726                     for (;;) {
727                         while (p >= prog_pathname && *p != '/')
728                             p--;
729                         if (p == prog_pathname) {
730                             /*
731                              * We're looking at the first component of
732                              * the pathname now, so we're definitely
733                              * not in a bundle, even if we're in
734                              * "/Contents".
735                              */
736                             break;
737                         }
738                         if (strncmp(p, "/Contents", component_end - p) == 0) {
739                             /* Found it. */
740                             appbundle_dir = (char *)g_malloc(p - prog_pathname + 1);
741                             memcpy(appbundle_dir, prog_pathname, p - prog_pathname);
742                             appbundle_dir[p - prog_pathname] = '\0';
743                             break;
744                         }
745                         component_end = p;
746                         p--;
747                     }
748                 }
749 #endif
750             }
751         }
752 
753         /*
754          * OK, we have the path we want.
755          */
756         progfile_dir = prog_pathname;
757         return NULL;
758     } else {
759         /*
760          * This "shouldn't happen"; we apparently
761          * have no "/" in the pathname.
762          * Just free up prog_pathname.
763          */
764         retstr = g_strdup_printf("No / found in \"%s\"", prog_pathname);
765         g_free(prog_pathname);
766         return retstr;
767     }
768 #endif
769 }
770 
771 /*
772  * Get the directory in which the program resides.
773  */
774 const char *
get_progfile_dir(void)775 get_progfile_dir(void)
776 {
777     return progfile_dir;
778 }
779 
780 /*
781  * Get the directory in which the global configuration and data files are
782  * stored.
783  *
784  * On Windows, we use the directory in which the executable for this
785  * process resides.
786  *
787  * On macOS (when executed from an app bundle), use a directory within
788  * that app bundle.
789  *
790  * Otherwise, if the program was executed from the build directory, use the
791  * directory in which the executable for this process resides. In all other
792  * cases, use the DATA_DIR value that was set at compile time.
793  *
794  * XXX - if we ever make libwireshark a real library, used by multiple
795  * applications (more than just TShark and versions of Wireshark with
796  * various UIs), should the configuration files belong to the library
797  * (and be shared by all those applications) or to the applications?
798  *
799  * If they belong to the library, that could be done on UNIX by the
800  * configure script, but it's trickier on Windows, as you can't just
801  * use the pathname of the executable.
802  *
803  * If they belong to the application, that could be done on Windows
804  * by using the pathname of the executable, but we'd have to have it
805  * passed in as an argument, in some call, on UNIX.
806  *
807  * Note that some of those configuration files might be used by code in
808  * libwireshark, some of them might be used by dissectors (would they
809  * belong to libwireshark, the application, or a separate library?),
810  * and some of them might be used by other code (the Wireshark preferences
811  * file includes resolver preferences that control the behavior of code
812  * in libwireshark, dissector preferences, and UI preferences, for
813  * example).
814  */
815 const char *
get_datafile_dir(void)816 get_datafile_dir(void)
817 {
818     if (datafile_dir != NULL)
819         return datafile_dir;
820 
821 #ifdef _WIN32
822     /*
823      * Do we have the pathname of the program?  If so, assume we're
824      * running an installed version of the program.  If we fail,
825      * we don't change "datafile_dir", and thus end up using the
826      * default.
827      *
828      * XXX - does NSIS put the installation directory into
829      * "\HKEY_LOCAL_MACHINE\SOFTWARE\Wireshark\InstallDir"?
830      * If so, perhaps we should read that from the registry,
831      * instead.
832      */
833     if (progfile_dir != NULL) {
834         /*
835          * Yes, we do; use that.
836          */
837         datafile_dir = g_strdup(progfile_dir);
838     } else {
839         /*
840          * No, we don't.
841          * Fall back on the default installation directory.
842          */
843         datafile_dir = g_strdup("C:\\Program Files\\Wireshark\\");
844     }
845 #else
846 
847     if (g_getenv("WIRESHARK_DATA_DIR") && !started_with_special_privs()) {
848         /*
849          * The user specified a different directory for data files
850          * and we aren't running with special privileges.
851          * XXX - We might be able to dispense with the priv check
852          */
853         datafile_dir = g_strdup(g_getenv("WIRESHARK_DATA_DIR"));
854     }
855 #ifdef __APPLE__
856     /*
857      * If we're running from an app bundle and weren't started
858      * with special privileges, use the Contents/Resources/share/wireshark
859      * subdirectory of the app bundle.
860      *
861      * (appbundle_dir is not set to a non-null value if we're
862      * started with special privileges, so we need only check
863      * it; we don't need to call started_with_special_privs().)
864      */
865     else if (appbundle_dir != NULL) {
866         datafile_dir = g_strdup_printf("%s/Contents/Resources/share/wireshark",
867                                        appbundle_dir);
868     }
869 #endif
870     else if (running_in_build_directory_flag && progfile_dir != NULL) {
871         /*
872          * We're (probably) being run from the build directory and
873          * weren't started with special privileges.
874          *
875          * (running_in_build_directory_flag is never set to TRUE
876          * if we're started with special privileges, so we need
877          * only check it; we don't need to call started_with_special_privs().)
878          *
879          * Data files (console.lua, radius/, etc.) are copied to the build
880          * directory during the build which also contains executables. A special
881          * exception is macOS (when built with an app bundle).
882          */
883         datafile_dir = g_strdup(progfile_dir);
884     } else {
885         datafile_dir = g_strdup(DATA_DIR);
886     }
887 
888 #endif
889     return datafile_dir;
890 }
891 
892 /*
893  * Find the directory where the plugins are stored.
894  *
895  * On Windows, we use the plugin\{VERSION} subdirectory of the datafile
896  * directory, where {VERSION} is the version number of this version of
897  * Wireshark.
898  *
899  * On UN*X:
900  *
901  *    if we appear to be run from the build directory, we use the
902  *    "plugin" subdirectory of the datafile directory;
903  *
904  *    otherwise, if the WIRESHARK_PLUGIN_DIR environment variable is
905  *    set and we aren't running with special privileges, we use the
906  *    value of that environment variable;
907  *
908  *    otherwise, if we're running from an app bundle in macOS, we
909  *    use the Contents/PlugIns/wireshark subdirectory of the app bundle;
910  *
911  *    otherwise, we use the PLUGIN_DIR value supplied by the
912  *    configure script.
913  */
914 static char *plugin_dir = NULL;
915 static char *plugin_dir_with_version = NULL;
916 static char *plugin_pers_dir = NULL;
917 static char *plugin_pers_dir_with_version = NULL;
918 
919 static void
init_plugin_dir(void)920 init_plugin_dir(void)
921 {
922 #if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
923 #ifdef _WIN32
924     /*
925      * On Windows, the data file directory is the installation
926      * directory; the plugins are stored under it.
927      *
928      * Assume we're running the installed version of Wireshark;
929      * on Windows, the data file directory is the directory
930      * in which the Wireshark binary resides.
931      */
932     plugin_dir = g_build_filename(get_datafile_dir(), "plugins", (gchar *)NULL);
933 
934     /*
935      * Make sure that pathname refers to a directory.
936      */
937     if (test_for_directory(plugin_dir) != EISDIR) {
938         /*
939          * Either it doesn't refer to a directory or it
940          * refers to something that doesn't exist.
941          *
942          * Assume that means we're running a version of
943          * Wireshark we've built in a build directory,
944          * in which case {datafile dir}\plugins is the
945          * top-level plugins source directory, and use
946          * that directory and set the "we're running in
947          * a build directory" flag, so the plugin
948          * scanner will check all subdirectories of that
949          * directory for plugins.
950          */
951         g_free(plugin_dir);
952         plugin_dir = g_build_filename(get_datafile_dir(), "plugins", (gchar *)NULL);
953         running_in_build_directory_flag = TRUE;
954     }
955 #else
956     if (running_in_build_directory_flag) {
957         /*
958          * We're (probably) being run from the build directory and
959          * weren't started with special privileges, so we'll use
960          * the "plugins" subdirectory of the directory where the program
961          * we're running is (that's the build directory).
962          */
963         plugin_dir = g_build_filename(get_progfile_dir(), "plugins", (gchar *)NULL);
964     } else {
965         if (g_getenv("WIRESHARK_PLUGIN_DIR") && !started_with_special_privs()) {
966             /*
967              * The user specified a different directory for plugins
968              * and we aren't running with special privileges.
969              */
970             plugin_dir = g_strdup(g_getenv("WIRESHARK_PLUGIN_DIR"));
971         }
972 #ifdef __APPLE__
973         /*
974          * If we're running from an app bundle and weren't started
975          * with special privileges, use the Contents/PlugIns/wireshark
976          * subdirectory of the app bundle.
977          *
978          * (appbundle_dir is not set to a non-null value if we're
979          * started with special privileges, so we need only check
980          * it; we don't need to call started_with_special_privs().)
981          */
982         else if (appbundle_dir != NULL) {
983             plugin_dir = g_build_filename(appbundle_dir, "Contents/PlugIns/wireshark", (gchar *)NULL);
984         }
985 #endif
986         else {
987             plugin_dir = g_strdup(PLUGIN_DIR);
988         }
989     }
990 #endif
991 #endif /* defined(HAVE_PLUGINS) || defined(HAVE_LUA) */
992 }
993 
994 static void
init_plugin_pers_dir(void)995 init_plugin_pers_dir(void)
996 {
997 #if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
998 #ifdef _WIN32
999     plugin_pers_dir = get_persconffile_path(PLUGINS_DIR_NAME, FALSE);
1000 #else
1001     plugin_pers_dir = g_build_filename(g_get_home_dir(), ".local/lib/wireshark/" PLUGINS_DIR_NAME, (gchar *)NULL);
1002 #endif
1003 #endif /* defined(HAVE_PLUGINS) || defined(HAVE_LUA) */
1004 }
1005 
1006 /*
1007  * Get the directory in which the plugins are stored.
1008  */
1009 const char *
get_plugins_dir(void)1010 get_plugins_dir(void)
1011 {
1012     if (!plugin_dir)
1013         init_plugin_dir();
1014     return plugin_dir;
1015 }
1016 
1017 const char *
get_plugins_dir_with_version(void)1018 get_plugins_dir_with_version(void)
1019 {
1020     if (!plugin_dir)
1021         init_plugin_dir();
1022     if (plugin_dir && !plugin_dir_with_version)
1023         plugin_dir_with_version = g_build_filename(plugin_dir, PLUGIN_PATH_ID, (gchar *)NULL);
1024     return plugin_dir_with_version;
1025 }
1026 
1027 /* Get the personal plugin dir */
1028 const char *
get_plugins_pers_dir(void)1029 get_plugins_pers_dir(void)
1030 {
1031     if (!plugin_pers_dir)
1032         init_plugin_pers_dir();
1033     return plugin_pers_dir;
1034 }
1035 
1036 const char *
get_plugins_pers_dir_with_version(void)1037 get_plugins_pers_dir_with_version(void)
1038 {
1039     if (!plugin_pers_dir)
1040         init_plugin_pers_dir();
1041     if (plugin_pers_dir && !plugin_pers_dir_with_version)
1042         plugin_pers_dir_with_version = g_build_filename(plugin_pers_dir, PLUGIN_PATH_ID, (gchar *)NULL);
1043     return plugin_pers_dir_with_version;
1044 }
1045 
1046 /*
1047  * Find the directory where the extcap hooks are stored.
1048  *
1049  * If the WIRESHARK_EXTCAP_DIR environment variable is set and we are not
1050  * running with special privileges, use that. Otherwise:
1051  *
1052  * On Windows, we use the "extcap" subdirectory of the datafile directory.
1053  *
1054  * On UN*X:
1055  *
1056  *    if we appear to be run from the build directory, we use the
1057  *    "extcap" subdirectory of the build directory.
1058  *
1059  *    otherwise, if we're running from an app bundle in macOS, we
1060  *    use the Contents/MacOS/extcap subdirectory of the app bundle;
1061  *
1062  *    otherwise, we use the EXTCAP_DIR value supplied by CMake.
1063  */
1064 static char *extcap_dir = NULL;
1065 
init_extcap_dir(void)1066 static void init_extcap_dir(void) {
1067     if (g_getenv("WIRESHARK_EXTCAP_DIR") && !started_with_special_privs()) {
1068         /*
1069          * The user specified a different directory for extcap hooks
1070          * and we aren't running with special privileges.
1071          */
1072         extcap_dir = g_strdup(g_getenv("WIRESHARK_EXTCAP_DIR"));
1073     }
1074 #ifdef _WIN32
1075     else {
1076         /*
1077          * On Windows, the data file directory is the installation
1078          * directory; the extcap hooks are stored under it.
1079          *
1080          * Assume we're running the installed version of Wireshark;
1081          * on Windows, the data file directory is the directory
1082          * in which the Wireshark binary resides.
1083          */
1084         extcap_dir = g_build_filename(get_datafile_dir(), "extcap", (gchar *)NULL);
1085     }
1086 #else
1087     else if (running_in_build_directory_flag) {
1088         /*
1089          * We're (probably) being run from the build directory and
1090          * weren't started with special privileges, so we'll use
1091          * the "extcap hooks" subdirectory of the directory where the program
1092          * we're running is (that's the build directory).
1093          */
1094         extcap_dir = g_build_filename(get_progfile_dir(), "extcap", (gchar *)NULL);
1095     }
1096 #ifdef __APPLE__
1097     else if (appbundle_dir != NULL) {
1098         /*
1099          * If we're running from an app bundle and weren't started
1100          * with special privileges, use the Contents/MacOS/extcap
1101          * subdirectory of the app bundle.
1102          *
1103          * (appbundle_dir is not set to a non-null value if we're
1104          * started with special privileges, so we need only check
1105          * it; we don't need to call started_with_special_privs().)
1106          */
1107         extcap_dir = g_build_filename(appbundle_dir, "Contents/MacOS/extcap", (gchar *)NULL);
1108     }
1109 #endif
1110     else {
1111         extcap_dir = g_strdup(EXTCAP_DIR);
1112     }
1113 #endif
1114 }
1115 
1116 /*
1117  * Get the directory in which the extcap hooks are stored.
1118  *
1119  */
1120 const char *
get_extcap_dir(void)1121 get_extcap_dir(void)
1122 {
1123     if (!extcap_dir)
1124         init_extcap_dir();
1125     return extcap_dir;
1126 }
1127 
1128 /*
1129  * Get the flag indicating whether we're running from a build
1130  * directory.
1131  */
1132 gboolean
running_in_build_directory(void)1133 running_in_build_directory(void)
1134 {
1135     return running_in_build_directory_flag;
1136 }
1137 
1138 /*
1139  * Get the directory in which files that, at least on UNIX, are
1140  * system files (such as "/etc/ethers") are stored; on Windows,
1141  * there's no "/etc" directory, so we get them from the global
1142  * configuration and data file directory.
1143  */
1144 const char *
get_systemfile_dir(void)1145 get_systemfile_dir(void)
1146 {
1147 #ifdef _WIN32
1148     return get_datafile_dir();
1149 #else
1150     return "/etc";
1151 #endif
1152 }
1153 
1154 void
set_profile_name(const gchar * profilename)1155 set_profile_name(const gchar *profilename)
1156 {
1157     g_free (persconfprofile);
1158 
1159     if (profilename && strlen(profilename) > 0 &&
1160         strcmp(profilename, DEFAULT_PROFILE) != 0) {
1161         persconfprofile = g_strdup (profilename);
1162     } else {
1163         /* Default Profile */
1164         persconfprofile = NULL;
1165     }
1166 }
1167 
1168 const char *
get_profile_name(void)1169 get_profile_name(void)
1170 {
1171     if (persconfprofile) {
1172         return persconfprofile;
1173     } else {
1174         return DEFAULT_PROFILE;
1175     }
1176 }
1177 
1178 gboolean
is_default_profile(void)1179 is_default_profile(void)
1180 {
1181     return (!persconfprofile || strcmp(persconfprofile, DEFAULT_PROFILE) == 0) ? TRUE : FALSE;
1182 }
1183 
1184 gboolean
has_global_profiles(void)1185 has_global_profiles(void)
1186 {
1187     WS_DIR *dir;
1188     WS_DIRENT *file;
1189     gchar *global_dir = get_global_profiles_dir();
1190     gchar *filename;
1191     gboolean has_global = FALSE;
1192 
1193     if ((test_for_directory(global_dir) == EISDIR) &&
1194         ((dir = ws_dir_open(global_dir, 0, NULL)) != NULL))
1195     {
1196         while ((file = ws_dir_read_name(dir)) != NULL) {
1197             filename = g_strdup_printf ("%s%s%s", global_dir, G_DIR_SEPARATOR_S,
1198                             ws_dir_get_name(file));
1199             if (test_for_directory(filename) == EISDIR) {
1200                 has_global = TRUE;
1201                 g_free (filename);
1202                 break;
1203             }
1204             g_free (filename);
1205         }
1206         ws_dir_close(dir);
1207     }
1208     g_free(global_dir);
1209     return has_global;
1210 }
1211 
1212 void
profile_store_persconffiles(gboolean store)1213 profile_store_persconffiles(gboolean store)
1214 {
1215     if (store) {
1216         profile_files = g_hash_table_new (g_str_hash, g_str_equal);
1217     }
1218     do_store_persconffiles = store;
1219 }
1220 
1221 void
profile_register_persconffile(const char * filename)1222 profile_register_persconffile(const char *filename)
1223 {
1224     if (do_store_persconffiles && !g_hash_table_lookup (profile_files, filename)) {
1225         /* Store filenames so we know which filenames belongs to a configuration profile */
1226         g_hash_table_insert (profile_files, g_strdup(filename), g_strdup(filename));
1227     }
1228 }
1229 
1230 /*
1231  * Get the directory in which personal configuration files reside.
1232  *
1233  * On Windows, it's "Wireshark", under %APPDATA% or, if %APPDATA% isn't set,
1234  * it's "%USERPROFILE%\Application Data" (which is what %APPDATA% normally
1235  * is on Windows 2000).
1236  *
1237  * On UNIX-compatible systems, we first look in XDG_CONFIG_HOME/wireshark
1238  * and, if that doesn't exist, ~/.wireshark, for backwards compatibility.
1239  * If neither exists, we use XDG_CONFIG_HOME/wireshark, so that the directory
1240  * is initially created as XDG_CONFIG_HOME/wireshark.  We use that regardless
1241  * of whether the user is running under an XDG desktop or not, so that
1242  * if the user's home directory is on a server and shared between
1243  * different desktop environments on different machines, they can all
1244  * share the same configuration file directory.
1245  *
1246  * XXX - what about stuff that shouldn't be shared between machines,
1247  * such as plugins in the form of shared loadable images?
1248  */
1249 static const char *
get_persconffile_dir_no_profile(void)1250 get_persconffile_dir_no_profile(void)
1251 {
1252     const char *env;
1253 
1254     /* Return the cached value, if available */
1255     if (persconffile_dir != NULL)
1256         return persconffile_dir;
1257 
1258     /*
1259      * See if the user has selected an alternate environment.
1260      */
1261     env = g_getenv(ENV_CONFIG_PATH_VAR);
1262 #ifdef _WIN32
1263     if (env == NULL) {
1264         /* for backward compatibility */
1265         env = g_getenv("WIRESHARK_APPDATA");
1266     }
1267 #endif
1268     if (env != NULL) {
1269         persconffile_dir = g_strdup(env);
1270         return persconffile_dir;
1271     }
1272 
1273 #ifdef _WIN32
1274     /*
1275      * Use %APPDATA% or %USERPROFILE%, so that configuration
1276      * files are stored in the user profile, rather than in
1277      * the home directory.  The Windows convention is to store
1278      * configuration information in the user profile, and doing
1279      * so means you can use Wireshark even if the home directory
1280      * is an inaccessible network drive.
1281      */
1282     env = g_getenv("APPDATA");
1283     if (env != NULL) {
1284         /*
1285          * Concatenate %APPDATA% with "\Wireshark".
1286          */
1287         persconffile_dir = g_build_filename(env, "Wireshark", NULL);
1288         return persconffile_dir;
1289     }
1290 
1291     /*
1292      * OK, %APPDATA% wasn't set, so use %USERPROFILE%\Application Data.
1293      */
1294     env = g_getenv("USERPROFILE");
1295     if (env != NULL) {
1296         persconffile_dir = g_build_filename(env, "Application Data", "Wireshark", NULL);
1297         return persconffile_dir;
1298     }
1299 
1300     /*
1301      * Give up and use "C:".
1302      */
1303     persconffile_dir = g_build_filename("C:", "Wireshark", NULL);
1304     return persconffile_dir;
1305 #else
1306     char *xdg_path, *path;
1307     struct passwd *pwd;
1308     const char *homedir;
1309 
1310     /*
1311      * Check if XDG_CONFIG_HOME/wireshark exists and is a directory.
1312      */
1313     xdg_path = g_build_filename(g_get_user_config_dir(), "wireshark", NULL);
1314     if (g_file_test(xdg_path, G_FILE_TEST_IS_DIR)) {
1315         persconffile_dir = xdg_path;
1316         return persconffile_dir;
1317     }
1318 
1319     /*
1320      * It doesn't exist, or it does but isn't a directory, so try
1321      * ~/.wireshark.
1322      *
1323      * If $HOME is set, use that for ~.
1324      *
1325      * (Note: before GLib 2.36, g_get_home_dir() didn't look at $HOME,
1326      * but we always want to do so, so we don't use g_get_home_dir().)
1327      */
1328     homedir = g_getenv("HOME");
1329     if (homedir == NULL) {
1330         /*
1331          * It's not set.
1332          *
1333          * Get their home directory from the password file.
1334          * If we can't even find a password file entry for them,
1335          * use "/tmp".
1336          */
1337         pwd = getpwuid(getuid());
1338         if (pwd != NULL) {
1339             homedir = pwd->pw_dir;
1340         } else {
1341             homedir = "/tmp";
1342         }
1343     }
1344     path = g_build_filename(homedir, ".wireshark", NULL);
1345     if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
1346         g_free(xdg_path);
1347         persconffile_dir = path;
1348         return persconffile_dir;
1349     }
1350 
1351     /*
1352      * Neither are directories that exist; use the XDG path, so we'll
1353      * create that as necessary.
1354      */
1355     g_free(path);
1356     persconffile_dir = xdg_path;
1357     return persconffile_dir;
1358 #endif
1359 }
1360 
1361 void
set_persconffile_dir(const char * p)1362 set_persconffile_dir(const char *p)
1363 {
1364     g_free(persconffile_dir);
1365     persconffile_dir = g_strdup(p);
1366 }
1367 
1368 char *
get_profiles_dir(void)1369 get_profiles_dir(void)
1370 {
1371     return g_strdup_printf ("%s%s%s", get_persconffile_dir_no_profile (),
1372                     G_DIR_SEPARATOR_S, PROFILES_DIR);
1373 }
1374 
1375 int
create_profiles_dir(char ** pf_dir_path_return)1376 create_profiles_dir(char **pf_dir_path_return)
1377 {
1378     char *pf_dir_path;
1379     ws_statb64 s_buf;
1380 
1381     /*
1382      * Create the "Default" personal configuration files directory, if necessary.
1383      */
1384     if (create_persconffile_profile (NULL, pf_dir_path_return) == -1) {
1385         return -1;
1386     }
1387 
1388     /*
1389      * Check if profiles directory exists.
1390      * If not then create it.
1391      */
1392     pf_dir_path = get_profiles_dir ();
1393     if (ws_stat64(pf_dir_path, &s_buf) != 0) {
1394         if (errno != ENOENT) {
1395             /* Some other problem; give up now. */
1396             *pf_dir_path_return = pf_dir_path;
1397             return -1;
1398         }
1399 
1400         /*
1401          * It doesn't exist; try to create it.
1402          */
1403         int ret = ws_mkdir(pf_dir_path, 0755);
1404         if (ret == -1) {
1405             *pf_dir_path_return = pf_dir_path;
1406             return ret;
1407         }
1408     }
1409     g_free(pf_dir_path);
1410 
1411     return 0;
1412 }
1413 
1414 char *
get_global_profiles_dir(void)1415 get_global_profiles_dir(void)
1416 {
1417     return g_strdup_printf ("%s%s%s", get_datafile_dir(),
1418                                G_DIR_SEPARATOR_S, PROFILES_DIR);
1419 }
1420 
1421 static char *
get_persconffile_dir(const gchar * profilename)1422 get_persconffile_dir(const gchar *profilename)
1423 {
1424     char *persconffile_profile_dir = NULL, *profile_dir;
1425 
1426     if (profilename && strlen(profilename) > 0 &&
1427         strcmp(profilename, DEFAULT_PROFILE) != 0) {
1428       profile_dir = get_profiles_dir();
1429       persconffile_profile_dir = g_strdup_printf ("%s%s%s", profile_dir,
1430                               G_DIR_SEPARATOR_S, profilename);
1431       g_free(profile_dir);
1432     } else {
1433       persconffile_profile_dir = g_strdup (get_persconffile_dir_no_profile ());
1434     }
1435 
1436     return persconffile_profile_dir;
1437 }
1438 
1439 char *
get_profile_dir(const char * profilename,gboolean is_global)1440 get_profile_dir(const char *profilename, gboolean is_global)
1441 {
1442     gchar *profile_dir;
1443 
1444     if (is_global) {
1445         if (profilename && strlen(profilename) > 0 &&
1446             strcmp(profilename, DEFAULT_PROFILE) != 0)
1447         {
1448             gchar *global_path = get_global_profiles_dir();
1449             profile_dir = g_build_filename(global_path, profilename, NULL);
1450             g_free(global_path);
1451         } else {
1452             profile_dir = g_strdup(get_datafile_dir());
1453         }
1454     } else {
1455         /*
1456          * If we didn't supply a profile name, i.e. if profilename is
1457          * null, get_persconffile_dir() returns the default profile.
1458          */
1459         profile_dir = get_persconffile_dir(profilename);
1460     }
1461 
1462     return profile_dir;
1463 }
1464 
1465 gboolean
profile_exists(const gchar * profilename,gboolean global)1466 profile_exists(const gchar *profilename, gboolean global)
1467 {
1468     gchar *path = NULL;
1469     gboolean exists;
1470 
1471     /*
1472      * If we're looking up a global profile, we must have a
1473      * profile name.
1474      */
1475     if (global && !profilename)
1476         return FALSE;
1477 
1478     path = get_profile_dir(profilename, global);
1479     exists = (test_for_directory(path) == EISDIR) ? TRUE : FALSE;
1480 
1481     g_free(path);
1482     return exists;
1483 }
1484 
1485 static int
delete_directory(const char * directory,char ** pf_dir_path_return)1486 delete_directory (const char *directory, char **pf_dir_path_return)
1487 {
1488     WS_DIR *dir;
1489     WS_DIRENT *file;
1490     gchar *filename;
1491     int ret = 0;
1492 
1493     if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) {
1494         while ((file = ws_dir_read_name(dir)) != NULL) {
1495             filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S,
1496                             ws_dir_get_name(file));
1497             if (test_for_directory(filename) != EISDIR) {
1498                 ret = ws_remove(filename);
1499 #if 0
1500             } else {
1501                 /* The user has manually created a directory in the profile directory */
1502                 /* I do not want to delete the directory recursively yet */
1503                 ret = delete_directory (filename, pf_dir_path_return);
1504 #endif
1505             }
1506             if (ret != 0) {
1507                 *pf_dir_path_return = filename;
1508                 break;
1509             }
1510             g_free (filename);
1511         }
1512         ws_dir_close(dir);
1513     }
1514 
1515     if (ret == 0 && (ret = ws_remove(directory)) != 0) {
1516         *pf_dir_path_return = g_strdup (directory);
1517     }
1518 
1519     return ret;
1520 }
1521 
1522 static int
reset_default_profile(char ** pf_dir_path_return)1523 reset_default_profile(char **pf_dir_path_return)
1524 {
1525     char *profile_dir = get_persconffile_dir(NULL);
1526     gchar *filename, *del_file;
1527     GList *files, *file;
1528     int ret = 0;
1529 
1530     files = g_hash_table_get_keys(profile_files);
1531     file = g_list_first(files);
1532     while (file) {
1533         filename = (gchar *)file->data;
1534         del_file = g_strdup_printf("%s%s%s", profile_dir, G_DIR_SEPARATOR_S, filename);
1535 
1536         if (file_exists(del_file)) {
1537             ret = ws_remove(del_file);
1538             if (ret != 0) {
1539                 *pf_dir_path_return = profile_dir;
1540                 g_free(del_file);
1541                 break;
1542             }
1543         }
1544 
1545         g_free(del_file);
1546         file = g_list_next(file);
1547     }
1548     g_list_free(files);
1549 
1550     g_free(profile_dir);
1551     return ret;
1552 }
1553 
1554 int
delete_persconffile_profile(const char * profilename,char ** pf_dir_path_return)1555 delete_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1556 {
1557     if (strcmp(profilename, DEFAULT_PROFILE) == 0) {
1558         return reset_default_profile(pf_dir_path_return);
1559     }
1560 
1561     char *profile_dir = get_persconffile_dir(profilename);
1562     int ret = 0;
1563 
1564     if (test_for_directory (profile_dir) == EISDIR) {
1565         ret = delete_directory (profile_dir, pf_dir_path_return);
1566     }
1567 
1568     g_free(profile_dir);
1569     return ret;
1570 }
1571 
1572 int
rename_persconffile_profile(const char * fromname,const char * toname,char ** pf_from_dir_path_return,char ** pf_to_dir_path_return)1573 rename_persconffile_profile(const char *fromname, const char *toname,
1574                 char **pf_from_dir_path_return, char **pf_to_dir_path_return)
1575 {
1576     char *from_dir = get_persconffile_dir(fromname);
1577     char *to_dir = get_persconffile_dir(toname);
1578     int ret = 0;
1579 
1580     ret = ws_rename (from_dir, to_dir);
1581     if (ret != 0) {
1582         *pf_from_dir_path_return = from_dir;
1583         *pf_to_dir_path_return = to_dir;
1584         return ret;
1585     }
1586 
1587     g_free (from_dir);
1588     g_free (to_dir);
1589 
1590     return 0;
1591 }
1592 
1593 /*
1594  * Create the directory that holds personal configuration files, if
1595  * necessary.  If we attempted to create it, and failed, return -1 and
1596  * set "*pf_dir_path_return" to the pathname of the directory we failed
1597  * to create (it's g_mallocated, so our caller should free it); otherwise,
1598  * return 0.
1599  */
1600 int
create_persconffile_profile(const char * profilename,char ** pf_dir_path_return)1601 create_persconffile_profile(const char *profilename, char **pf_dir_path_return)
1602 {
1603     char *pf_dir_path;
1604 #ifdef _WIN32
1605     char *pf_dir_path_copy, *pf_dir_parent_path;
1606     size_t pf_dir_parent_path_len;
1607     int save_errno;
1608 #endif
1609     ws_statb64 s_buf;
1610     int ret;
1611 
1612     if (profilename) {
1613         /*
1614          * Create the personal profiles directory, if necessary.
1615          */
1616         if (create_profiles_dir(pf_dir_path_return) == -1) {
1617             return -1;
1618         }
1619     }
1620 
1621     pf_dir_path = get_persconffile_dir(profilename);
1622     if (ws_stat64(pf_dir_path, &s_buf) != 0) {
1623         if (errno != ENOENT) {
1624             /* Some other problem; give up now. */
1625             *pf_dir_path_return = pf_dir_path;
1626             return -1;
1627         }
1628 #ifdef _WIN32
1629         /*
1630          * Does the parent directory of that directory
1631          * exist?  %APPDATA% may not exist even though
1632          * %USERPROFILE% does.
1633          *
1634          * We check for the existence of the directory
1635          * by first checking whether the parent directory
1636          * is just a drive letter and, if it's not, by
1637          * doing a "stat()" on it.  If it's a drive letter,
1638          * or if the "stat()" succeeds, we assume it exists.
1639          */
1640         pf_dir_path_copy = g_strdup(pf_dir_path);
1641         pf_dir_parent_path = get_dirname(pf_dir_path_copy);
1642         pf_dir_parent_path_len = strlen(pf_dir_parent_path);
1643         if (pf_dir_parent_path_len > 0
1644             && pf_dir_parent_path[pf_dir_parent_path_len - 1] != ':'
1645             && ws_stat64(pf_dir_parent_path, &s_buf) != 0) {
1646             /*
1647              * Not a drive letter and the stat() failed.
1648              */
1649             if (errno != ENOENT) {
1650                 /* Some other problem; give up now. */
1651                 *pf_dir_path_return = pf_dir_path;
1652                 save_errno = errno;
1653                 g_free(pf_dir_path_copy);
1654                 errno = save_errno;
1655                 return -1;
1656             }
1657             /*
1658              * No, it doesn't exist - make it first.
1659              */
1660             ret = ws_mkdir(pf_dir_parent_path, 0755);
1661             if (ret == -1) {
1662                 *pf_dir_path_return = pf_dir_parent_path;
1663                 save_errno = errno;
1664                 g_free(pf_dir_path);
1665                 errno = save_errno;
1666                 return -1;
1667             }
1668         }
1669         g_free(pf_dir_path_copy);
1670         ret = ws_mkdir(pf_dir_path, 0755);
1671 #else
1672         ret = g_mkdir_with_parents(pf_dir_path, 0755);
1673 #endif
1674     } else {
1675         /*
1676          * Something with that pathname exists; if it's not
1677          * a directory, we'll get an error if we try to put
1678          * something in it, so we don't fail here, we wait
1679          * for that attempt to fail.
1680          */
1681         ret = 0;
1682     }
1683     if (ret == -1)
1684         *pf_dir_path_return = pf_dir_path;
1685     else
1686         g_free(pf_dir_path);
1687 
1688     return ret;
1689 }
1690 
1691 const GHashTable *
allowed_profile_filenames(void)1692 allowed_profile_filenames(void)
1693 {
1694     return profile_files;
1695 }
1696 
1697 int
create_persconffile_dir(char ** pf_dir_path_return)1698 create_persconffile_dir(char **pf_dir_path_return)
1699 {
1700     return create_persconffile_profile(persconfprofile, pf_dir_path_return);
1701 }
1702 
1703 int
copy_persconffile_profile(const char * toname,const char * fromname,gboolean from_global,char ** pf_filename_return,char ** pf_to_dir_path_return,char ** pf_from_dir_path_return)1704 copy_persconffile_profile(const char *toname, const char *fromname, gboolean from_global,
1705               char **pf_filename_return, char **pf_to_dir_path_return, char **pf_from_dir_path_return)
1706 {
1707     int ret = 0;
1708     gchar *from_dir;
1709     gchar *to_dir = get_persconffile_dir(toname);
1710     gchar *filename, *from_file, *to_file;
1711     GList *files, *file;
1712 
1713     from_dir = get_profile_dir(fromname, from_global);
1714 
1715     files = g_hash_table_get_keys(profile_files);
1716     file = g_list_first(files);
1717     while (file) {
1718         filename = (gchar *)file->data;
1719         from_file = g_strdup_printf ("%s%s%s", from_dir, G_DIR_SEPARATOR_S, filename);
1720         to_file =  g_strdup_printf ("%s%s%s", to_dir, G_DIR_SEPARATOR_S, filename);
1721 
1722         if (file_exists(from_file) && !copy_file_binary_mode(from_file, to_file)) {
1723             *pf_filename_return = g_strdup(filename);
1724             *pf_to_dir_path_return = to_dir;
1725             *pf_from_dir_path_return = from_dir;
1726             g_free (from_file);
1727             g_free (to_file);
1728             ret = -1;
1729             break;
1730         }
1731 
1732         g_free (from_file);
1733         g_free (to_file);
1734 
1735         file = g_list_next(file);
1736     }
1737 
1738     g_list_free (files);
1739     g_free (from_dir);
1740     g_free (to_dir);
1741 
1742     return ret;
1743 }
1744 
1745 /*
1746  * Get the (default) directory in which personal data is stored.
1747  *
1748  * On Win32, this is the "My Documents" folder in the personal profile.
1749  * On UNIX this is simply the current directory.
1750  */
1751 /* XXX - should this and the get_home_dir() be merged? */
1752 extern const char *
get_persdatafile_dir(void)1753 get_persdatafile_dir(void)
1754 {
1755 #ifdef _WIN32
1756     TCHAR tszPath[MAX_PATH];
1757 
1758     /* Return the cached value, if available */
1759     if (persdatafile_dir != NULL)
1760         return persdatafile_dir;
1761 
1762     /*
1763      * Hint: SHGetFolderPath is not available on MSVC 6 - without
1764      * Platform SDK
1765      */
1766     if (SHGetSpecialFolderPath(NULL, tszPath, CSIDL_PERSONAL, FALSE)) {
1767         persdatafile_dir = g_utf16_to_utf8(tszPath, -1, NULL, NULL, NULL);
1768         return persdatafile_dir;
1769     } else {
1770         return "";
1771     }
1772 #else
1773     return "";
1774 #endif
1775 }
1776 
1777 void
set_persdatafile_dir(const char * p)1778 set_persdatafile_dir(const char *p)
1779 {
1780     g_free(persdatafile_dir);
1781     persdatafile_dir = g_strdup(p);
1782 }
1783 
1784 #ifdef _WIN32
1785 /*
1786  * Returns the user's home directory on Win32.
1787  */
1788 static const char *
get_home_dir(void)1789 get_home_dir(void)
1790 {
1791     static const char *home = NULL;
1792     const char *homedrive, *homepath;
1793     char *homestring;
1794     char *lastsep;
1795 
1796     /* Return the cached value, if available */
1797     if (home)
1798         return home;
1799 
1800     /*
1801      * XXX - should we use USERPROFILE anywhere in this process?
1802      * Is there a chance that it might be set but one or more of
1803      * HOMEDRIVE or HOMEPATH isn't set?
1804      */
1805     homedrive = g_getenv("HOMEDRIVE");
1806     if (homedrive != NULL) {
1807         homepath = g_getenv("HOMEPATH");
1808         if (homepath != NULL) {
1809             /*
1810              * This is cached, so we don't need to worry about
1811              * allocating multiple ones of them.
1812              */
1813             homestring = g_strdup_printf("%s%s", homedrive, homepath);
1814 
1815             /*
1816              * Trim off any trailing slash or backslash.
1817              */
1818             lastsep = find_last_pathname_separator(homestring);
1819             if (lastsep != NULL && *(lastsep + 1) == '\0') {
1820                 /*
1821                  * Last separator is the last character
1822                  * in the string.  Nuke it.
1823                  */
1824                 *lastsep = '\0';
1825             }
1826             home = homestring;
1827         } else
1828             home = homedrive;
1829     } else {
1830         /*
1831          * Give up and use C:.
1832          */
1833         home = "C:";
1834     }
1835 
1836     return home;
1837 }
1838 #endif
1839 
1840 /*
1841  * Construct the path name of a personal configuration file, given the
1842  * file name.
1843  *
1844  * On Win32, if "for_writing" is FALSE, we check whether the file exists
1845  * and, if not, construct a path name relative to the ".wireshark"
1846  * subdirectory of the user's home directory, and check whether that
1847  * exists; if it does, we return that, so that configuration files
1848  * from earlier versions can be read.
1849  *
1850  * The returned file name was g_malloc()'d so it must be g_free()d when the
1851  * caller is done with it.
1852  */
1853 char *
get_persconffile_path(const char * filename,gboolean from_profile)1854 get_persconffile_path(const char *filename, gboolean from_profile)
1855 {
1856     char *path, *dir = NULL;
1857 
1858     if (from_profile) {
1859         /* Store filenames so we know which filenames belongs to a configuration profile */
1860         profile_register_persconffile(filename);
1861 
1862         dir = get_persconffile_dir(persconfprofile);
1863     } else {
1864         dir = get_persconffile_dir(NULL);
1865     }
1866     path = g_build_filename(dir, filename, NULL);
1867 
1868     g_free(dir);
1869     return path;
1870 }
1871 
1872 /*
1873  * Construct the path name of a global configuration file, given the
1874  * file name.
1875  *
1876  * The returned file name was g_malloc()'d so it must be g_free()d when the
1877  * caller is done with it.
1878  */
1879 char *
get_datafile_path(const char * filename)1880 get_datafile_path(const char *filename)
1881 {
1882     if (running_in_build_directory_flag &&
1883         (!strcmp(filename, "AUTHORS-SHORT") ||
1884          !strcmp(filename, "hosts"))) {
1885         /* We're running in the build directory and the requested file is a
1886          * generated (or a test) file.  Return the file name in the build
1887          * directory (not in the source/data directory).
1888          * (Oh the things we do to keep the source directory pristine...)
1889          */
1890         return g_build_filename(get_progfile_dir(), filename, (char *)NULL);
1891     } else {
1892         return g_build_filename(get_datafile_dir(), filename, (char *)NULL);
1893     }
1894 }
1895 
1896 /*
1897  * Return an error message for UNIX-style errno indications on open or
1898  * create operations.
1899  */
1900 const char *
file_open_error_message(int err,gboolean for_writing)1901 file_open_error_message(int err, gboolean for_writing)
1902 {
1903     const char *errmsg;
1904     static char errmsg_errno[1024+1];
1905 
1906     switch (err) {
1907 
1908     case ENOENT:
1909         if (for_writing)
1910             errmsg = "The path to the file \"%s\" doesn't exist.";
1911         else
1912             errmsg = "The file \"%s\" doesn't exist.";
1913         break;
1914 
1915     case EACCES:
1916         if (for_writing)
1917             errmsg = "You don't have permission to create or write to the file \"%s\".";
1918         else
1919             errmsg = "You don't have permission to read the file \"%s\".";
1920         break;
1921 
1922     case EISDIR:
1923         errmsg = "\"%s\" is a directory (folder), not a file.";
1924         break;
1925 
1926     case ENOSPC:
1927         errmsg = "The file \"%s\" could not be created because there is no space left on the file system.";
1928         break;
1929 
1930 #ifdef EDQUOT
1931     case EDQUOT:
1932         errmsg = "The file \"%s\" could not be created because you are too close to, or over, your disk quota.";
1933         break;
1934 #endif
1935 
1936     case EINVAL:
1937         errmsg = "The file \"%s\" could not be created because an invalid filename was specified.";
1938         break;
1939 
1940 #ifdef ENAMETOOLONG
1941     case ENAMETOOLONG:
1942         /* XXX Make sure we truncate on a character boundary. */
1943         errmsg = "The file name \"%.80s" UTF8_HORIZONTAL_ELLIPSIS "\" is too long.";
1944         break;
1945 #endif
1946 
1947     case ENOMEM:
1948         /*
1949          * The problem probably has nothing to do with how much RAM the
1950          * user has on their machine, so don't confuse them by saying
1951          * "memory".  The problem is probably either virtual address
1952          * space or swap space.
1953          */
1954 #if GLIB_SIZEOF_VOID_P == 4
1955         /*
1956          * ILP32; we probably ran out of virtual address space.
1957          */
1958 #define ENOMEM_REASON "it can't be handled by a 32-bit application"
1959 #else
1960         /*
1961          * LP64 or LLP64; we probably ran out of swap space.
1962          */
1963 #if defined(_WIN32)
1964         /*
1965          * You need to make the pagefile bigger.
1966          */
1967 #define ENOMEM_REASON "the pagefile is too small"
1968 #elif defined(__APPLE__)
1969         /*
1970          * dynamic_pager couldn't, or wouldn't, create more swap files.
1971          */
1972 #define ENOMEM_REASON "your system ran out of swap file space"
1973 #else
1974         /*
1975          * Either you have a fixed swap partition or a fixed swap file,
1976          * and it needs to be made bigger.
1977          *
1978          * This is UN*X, but it's not macOS, so we assume the user is
1979          * *somewhat* nerdy.
1980          */
1981 #define ENOMEM_REASON "your system is out of swap space"
1982 #endif
1983 #endif /* GLIB_SIZEOF_VOID_P == 4 */
1984         if (for_writing)
1985             errmsg = "The file \"%s\" could not be created because " ENOMEM_REASON ".";
1986         else
1987             errmsg = "The file \"%s\" could not be opened because " ENOMEM_REASON ".";
1988         break;
1989 
1990     default:
1991         g_snprintf(errmsg_errno, sizeof(errmsg_errno),
1992                "The file \"%%s\" could not be %s: %s.",
1993                for_writing ? "created" : "opened",
1994                g_strerror(err));
1995         errmsg = errmsg_errno;
1996         break;
1997     }
1998     return errmsg;
1999 }
2000 
2001 /*
2002  * Return an error message for UNIX-style errno indications on write
2003  * operations.
2004  */
2005 const char *
file_write_error_message(int err)2006 file_write_error_message(int err)
2007 {
2008     const char *errmsg;
2009     static char errmsg_errno[1024+1];
2010 
2011     switch (err) {
2012 
2013     case ENOSPC:
2014         errmsg = "The file \"%s\" could not be saved because there is no space left on the file system.";
2015         break;
2016 
2017 #ifdef EDQUOT
2018     case EDQUOT:
2019         errmsg = "The file \"%s\" could not be saved because you are too close to, or over, your disk quota.";
2020         break;
2021 #endif
2022 
2023     default:
2024         g_snprintf(errmsg_errno, sizeof(errmsg_errno),
2025                "An error occurred while writing to the file \"%%s\": %s.",
2026                g_strerror(err));
2027         errmsg = errmsg_errno;
2028         break;
2029     }
2030     return errmsg;
2031 }
2032 
2033 
2034 gboolean
file_exists(const char * fname)2035 file_exists(const char *fname)
2036 {
2037     ws_statb64 file_stat;
2038 
2039     if (!fname) {
2040         return FALSE;
2041     }
2042 
2043     if (ws_stat64(fname, &file_stat) != 0 && errno == ENOENT) {
2044         return FALSE;
2045     } else {
2046         return TRUE;
2047     }
2048 }
2049 
config_file_exists_with_entries(const char * fname,char comment_char)2050 gboolean config_file_exists_with_entries(const char *fname, char comment_char)
2051 {
2052     gboolean start_of_line = TRUE;
2053     gboolean has_entries = FALSE;
2054     FILE *file;
2055     int c;
2056 
2057     if (!fname) {
2058         return FALSE;
2059     }
2060 
2061     if ((file = ws_fopen(fname, "r")) == NULL) {
2062         return FALSE;
2063     }
2064 
2065     do {
2066         c = ws_getc_unlocked(file);
2067         if (start_of_line && c != comment_char && !g_ascii_isspace(c) && g_ascii_isprint(c)) {
2068             has_entries = TRUE;
2069             break;
2070         }
2071         if (c == '\n' || !g_ascii_isspace(c)) {
2072             start_of_line = (c == '\n');
2073         }
2074     } while (c != EOF);
2075 
2076     fclose(file);
2077     return has_entries;
2078 }
2079 
2080 /*
2081  * Check that the from file is not the same as to file
2082  * We do it here so we catch all cases ...
2083  * Unfortunately, the file requester gives us an absolute file
2084  * name and the read file name may be relative (if supplied on
2085  * the command line), so we can't just compare paths. From Joerg Mayer.
2086  */
2087 gboolean
files_identical(const char * fname1,const char * fname2)2088 files_identical(const char *fname1, const char *fname2)
2089 {
2090     /* Two different implementations, because:
2091      *
2092      * - _fullpath is not available on UN*X, so we can't get full
2093      *   paths and compare them (which wouldn't work with hard links
2094      *   in any case);
2095      *
2096      * - st_ino isn't filled in with a meaningful value on Windows.
2097      */
2098 #ifdef _WIN32
2099     char full1[MAX_PATH], full2[MAX_PATH];
2100 
2101     /*
2102      * Get the absolute full paths of the file and compare them.
2103      * That won't work if you have hard links, but those aren't
2104      * much used on Windows, even though NTFS supports them.
2105      *
2106      * XXX - will _fullpath work with UNC?
2107      */
2108     if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
2109         return FALSE;
2110     }
2111 
2112     if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
2113         return FALSE;
2114     }
2115 
2116     if(strcmp(full1, full2) == 0) {
2117         return TRUE;
2118     } else {
2119         return FALSE;
2120     }
2121 #else
2122     ws_statb64 filestat1, filestat2;
2123 
2124     /*
2125      * Compare st_dev and st_ino.
2126      */
2127     if (ws_stat64(fname1, &filestat1) == -1)
2128         return FALSE;   /* can't get info about the first file */
2129     if (ws_stat64(fname2, &filestat2) == -1)
2130         return FALSE;   /* can't get info about the second file */
2131     return (filestat1.st_dev == filestat2.st_dev &&
2132         filestat1.st_ino == filestat2.st_ino);
2133 #endif
2134 }
2135 
2136 gboolean
file_needs_reopen(int fd,const char * filename)2137 file_needs_reopen(int fd, const char* filename)
2138 {
2139 #ifdef _WIN32
2140     /* Windows handles st_dev in a way unsuitable here:
2141      *   * _fstat() simply casts the file descriptor (ws_fileno(fp)) to unsigned
2142      *     and assigns this value to st_dev and st_rdev
2143      *   * _wstat() converts drive letter (eg. C) to number (A=0, B=1, C=2, ...)
2144      *     and assigns such number to st_dev and st_rdev
2145      *
2146      * The st_ino parameter is simply zero as there is no specific assignment
2147      * to it in the Universal CRT source code.
2148      *
2149      * Thus instead of using fstat(), use Windows specific API.
2150      */
2151 
2152     HANDLE open_handle = (HANDLE)_get_osfhandle(fd);
2153     HANDLE current_handle = CreateFile(utf_8to16(filename), FILE_READ_ATTRIBUTES,
2154                             FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
2155                             NULL, OPEN_EXISTING, 0, NULL);
2156     BY_HANDLE_FILE_INFORMATION open_info, current_info;
2157 
2158     if (current_handle == INVALID_HANDLE_VALUE) {
2159         return TRUE;
2160     }
2161 
2162 #if (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
2163     FILE_ID_INFO open_id, current_id;
2164     if (GetFileInformationByHandleEx(open_handle, FileIdInfo, &open_id, sizeof(open_id)) &&
2165         GetFileInformationByHandleEx(current_handle, FileIdInfo, &current_id, sizeof(current_id))) {
2166         /* 128-bit identifier is available, use it */
2167         CloseHandle(current_handle);
2168         return open_id.VolumeSerialNumber != current_id.VolumeSerialNumber ||
2169                memcmp(&open_id.FileId, &current_id.FileId, sizeof(open_id.FileId)) != 0;
2170     }
2171 #endif /* _WIN32_WINNT >= _WIN32_WINNT_WIN8 */
2172     if (GetFileInformationByHandle(open_handle, &open_info) &&
2173         GetFileInformationByHandle(current_handle, &current_info)) {
2174         /* Fallback to 64-bit identifier */
2175         CloseHandle(current_handle);
2176         guint64 open_size = (((guint64)open_info.nFileSizeHigh) << 32) | open_info.nFileSizeLow;
2177         guint64 current_size = (((guint64)current_info.nFileSizeHigh) << 32) | current_info.nFileSizeLow;
2178         return open_info.dwVolumeSerialNumber != current_info.dwVolumeSerialNumber ||
2179                open_info.nFileIndexHigh != current_info.nFileIndexHigh ||
2180                open_info.nFileIndexLow != current_info.nFileIndexLow ||
2181                open_size > current_size;
2182     }
2183     CloseHandle(current_handle);
2184     return TRUE;
2185 #else
2186     ws_statb64 open_stat, current_stat;
2187 
2188     /* consider a file deleted when stat fails for either file,
2189      * or when the residing device / inode has changed. */
2190     if (0 != ws_fstat64(fd, &open_stat))
2191         return TRUE;
2192     if (0 != ws_stat64(filename, &current_stat))
2193         return TRUE;
2194 
2195     return open_stat.st_dev != current_stat.st_dev ||
2196            open_stat.st_ino != current_stat.st_ino ||
2197            open_stat.st_size > current_stat.st_size;
2198 #endif
2199 }
2200 
2201 gboolean
write_file_binary_mode(const char * filename,const void * content,size_t content_len)2202 write_file_binary_mode(const char *filename, const void *content, size_t content_len)
2203 {
2204     int fd;
2205     size_t bytes_left;
2206     unsigned int bytes_to_write;
2207     ssize_t bytes_written;
2208     const guint8 *ptr;
2209     int err;
2210 
2211     fd = ws_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
2212     if (fd == -1) {
2213         report_open_failure(filename, errno, TRUE);
2214         return FALSE;
2215     }
2216 
2217     /*
2218      * The third argument to _write() on Windows is an unsigned int,
2219      * so, on Windows, that's the size of the third argument to
2220      * ws_write().
2221      *
2222      * The third argument to write() on UN*X is a size_t, although
2223      * the return value is an ssize_t, so one probably shouldn't
2224      * write more than the max value of an ssize_t.
2225      *
2226      * In either case, there's no guarantee that a size_t such as
2227      * content_len can be passed to ws_write(), so we write in
2228      * chunks of at most 2^31 bytes.
2229      */
2230 
2231     ptr = (const guint8 *)content;
2232     bytes_left = content_len;
2233     while (bytes_left != 0) {
2234         if (bytes_left > 0x40000000) {
2235             bytes_to_write = 0x40000000;
2236         } else {
2237             bytes_to_write = (unsigned int)bytes_left;
2238         }
2239         bytes_written = ws_write(fd, ptr, bytes_to_write);
2240         if (bytes_written <= 0) {
2241             if (bytes_written < 0) {
2242                 err = errno;
2243             } else {
2244                 err = WTAP_ERR_SHORT_WRITE;
2245             }
2246             report_write_failure(filename, err);
2247             ws_close(fd);
2248             return FALSE;
2249         }
2250         bytes_left -= bytes_written;
2251         ptr += bytes_written;
2252     }
2253 
2254     ws_close(fd);
2255     return TRUE;
2256 }
2257 
2258 /*
2259  * Copy a file in binary mode, for those operating systems that care about
2260  * such things.  This should be OK for all files, even text files, as
2261  * we'll copy the raw bytes, and we don't look at the bytes as we copy
2262  * them.
2263  *
2264  * Returns TRUE on success, FALSE on failure. If a failure, it also
2265  * displays a simple dialog window with the error message.
2266  */
2267 gboolean
copy_file_binary_mode(const char * from_filename,const char * to_filename)2268 copy_file_binary_mode(const char *from_filename, const char *to_filename)
2269 {
2270     int           from_fd, to_fd, err;
2271     ssize_t       nread, nwritten;
2272     guint8        *pd = NULL;
2273 
2274     /* Copy the raw bytes of the file. */
2275     from_fd = ws_open(from_filename, O_RDONLY | O_BINARY, 0000 /* no creation so don't matter */);
2276     if (from_fd < 0) {
2277         report_open_failure(from_filename, errno, FALSE);
2278         goto done;
2279     }
2280 
2281     /* Use open() instead of creat() so that we can pass the O_BINARY
2282        flag, which is relevant on Win32; it appears that "creat()"
2283        may open the file in text mode, not binary mode, but we want
2284        to copy the raw bytes of the file, so we need the output file
2285        to be open in binary mode. */
2286     to_fd = ws_open(to_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
2287     if (to_fd < 0) {
2288         report_open_failure(to_filename, errno, TRUE);
2289         ws_close(from_fd);
2290         goto done;
2291     }
2292 
2293 #define FS_READ_SIZE 65536
2294     pd = (guint8 *)g_malloc(FS_READ_SIZE);
2295     while ((nread = ws_read(from_fd, pd, FS_READ_SIZE)) > 0) {
2296         nwritten = ws_write(to_fd, pd, nread);
2297         if (nwritten < nread) {
2298             if (nwritten < 0)
2299                 err = errno;
2300             else
2301                 err = WTAP_ERR_SHORT_WRITE;
2302             report_write_failure(to_filename, err);
2303             ws_close(from_fd);
2304             ws_close(to_fd);
2305             goto done;
2306         }
2307     }
2308     if (nread < 0) {
2309         err = errno;
2310         report_read_failure(from_filename, err);
2311         ws_close(from_fd);
2312         ws_close(to_fd);
2313         goto done;
2314     }
2315     ws_close(from_fd);
2316     if (ws_close(to_fd) < 0) {
2317         report_write_failure(to_filename, errno);
2318         goto done;
2319     }
2320 
2321     g_free(pd);
2322     pd = NULL;
2323     return TRUE;
2324 
2325 done:
2326     g_free(pd);
2327     return FALSE;
2328 }
2329 
2330 gchar *
data_file_url(const gchar * filename)2331 data_file_url(const gchar *filename)
2332 {
2333     gchar *file_path;
2334     gchar *uri;
2335 
2336     /* Absolute path? */
2337     if(g_path_is_absolute(filename)) {
2338         file_path = g_strdup(filename);
2339     } else {
2340         file_path = g_strdup_printf("%s/%s", get_datafile_dir(), filename);
2341     }
2342 
2343     /* XXX - check, if the file is really existing, otherwise display a simple_dialog about the problem */
2344 
2345     /* convert filename to uri */
2346     uri = g_filename_to_uri(file_path, NULL, NULL);
2347     g_free(file_path);
2348     return uri;
2349 }
2350 
2351 void
free_progdirs(void)2352 free_progdirs(void)
2353 {
2354     g_free(persconffile_dir);
2355     persconffile_dir = NULL;
2356     g_free(datafile_dir);
2357     datafile_dir = NULL;
2358     g_free(persdatafile_dir);
2359     persdatafile_dir = NULL;
2360     g_free(persconfprofile);
2361     persconfprofile = NULL;
2362     g_free(progfile_dir);
2363     progfile_dir = NULL;
2364 #if defined(HAVE_PLUGINS) || defined(HAVE_LUA)
2365     g_free(plugin_dir);
2366     plugin_dir = NULL;
2367     g_free(plugin_dir_with_version);
2368     plugin_dir_with_version = NULL;
2369     g_free(plugin_pers_dir);
2370     plugin_pers_dir = NULL;
2371     g_free(plugin_pers_dir_with_version);
2372     plugin_pers_dir_with_version = NULL;
2373 #endif
2374     g_free(extcap_dir);
2375     extcap_dir = NULL;
2376 }
2377 
2378 /*
2379  * Editor modelines
2380  *
2381  * Local Variables:
2382  * c-basic-offset: 4
2383  * tab-width: 8
2384  * indent-tabs-mode: nil
2385  * End:
2386  *
2387  * ex: set shiftwidth=4 tabstop=8 expandtab:
2388  * :indentSize=4:tabSize=8:noTabs=true:
2389  */
2390