Coverage Report

Created: 2025-04-03 08:43

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