Coverage Report

Created: 2026-01-02 06:13

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