epan: use json_dumper for json outputs.
[metze/wireshark/wip.git] / wsutil / file_util.c
1 /* file_util.c
2  *
3  * (Originally part of the Wiretap Library, now part of the Wireshark
4  *  utility library)
5  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 /*
11  * File wrapper functions to replace the file functions from GLib like
12  * g_open().
13  *
14  * With MSVC, code using the C support library from one version of MSVC
15  * cannot use file descriptors or FILE *'s returned from code using
16  * the C support library from another version of MSVC.
17  *
18  * We therefore provide our own versions of the routines to open files,
19  * so that they're built to use the same C support library as our code
20  * that reads them.
21  *
22  * (If both were built to use the Universal CRT:
23  *
24  *    http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx
25  *
26  * this would not be a problem.)
27  *
28  * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS
29  * FROM file_util.h INSTEAD!!!
30  *
31  * The following code is stripped down code copied from the GLib file
32  * glib/gstdio.h - stripped down because this is used only on Windows
33  * and we use only wide char functions.
34  *
35  * In addition, we have our own ws_stdio_stat64(), which uses
36  * _wstati64(), so that we can get file sizes for files > 4 GB in size.
37  *
38  * XXX - is there any reason why we supply our own versions of routines
39  * that *don't* return file descriptors, other than ws_stdio_stat64()?
40  * Is there an issue with UTF-16 support in _wmkdir() with some versions
41  * of the C runtime, so that if GLib is built to use that version, it
42  * won't handle UTF-16 paths?
43  */
44
45 #ifndef _WIN32
46 #error "This is only for Windows"
47 #endif
48
49 #include "config.h"
50
51 #include <glib.h>
52
53 #include <windows.h>
54 #include <errno.h>
55 #include <wchar.h>
56 #include <tchar.h>
57 #include <stdlib.h>
58
59 #include "file_util.h"
60
61 static gchar *program_path = NULL;
62 static gchar *system_path = NULL;
63 static gchar *npcap_path = NULL;
64
65 /**
66  * g_open:
67  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
68  * @flags: as in open()
69  * @mode: as in open()
70  *
71  * A wrapper for the POSIX open() function. The open() function is
72  * used to convert a pathname into a file descriptor. Note that on
73  * POSIX systems file descriptors are implemented by the operating
74  * system. On Windows, it's the C library that implements open() and
75  * file descriptors. The actual Windows API for opening files is
76  * something different.
77  *
78  * See the C library manual for more details about open().
79  *
80  * Returns: a new file descriptor, or -1 if an error occurred. The
81  * return value can be used exactly like the return value from open().
82  *
83  * Since: 2.6
84  */
85 int
86 ws_stdio_open (const gchar *filename, int flags, int mode)
87 {
88     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
89     int retval;
90     int save_errno;
91
92     if (wfilename == NULL)
93     {
94         errno = EINVAL;
95         return -1;
96     }
97
98     retval = _wopen (wfilename, flags, mode);
99     save_errno = errno;
100
101     g_free (wfilename);
102
103     errno = save_errno;
104     return retval;
105 }
106
107
108 /**
109  * g_rename:
110  * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
111  * @newfilename: a pathname in the GLib file name encoding
112  *
113  * A wrapper for the POSIX rename() function. The rename() function
114  * renames a file, moving it between directories if required.
115  *
116  * See your C library manual for more details about how rename() works
117  * on your system. Note in particular that on Win9x it is not possible
118  * to rename a file if a file with the new name already exists. Also
119  * it is not possible in general on Windows to rename an open file.
120  *
121  * Returns: 0 if the renaming succeeded, -1 if an error occurred
122  *
123  * Since: 2.6
124  */
125 int
126 ws_stdio_rename (const gchar *oldfilename, const gchar *newfilename)
127 {
128     wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
129     wchar_t *wnewfilename;
130     int retval;
131     int save_errno = 0;
132
133     if (woldfilename == NULL)
134     {
135         errno = EINVAL;
136         return -1;
137     }
138
139     wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
140
141     if (wnewfilename == NULL)
142     {
143         g_free (woldfilename);
144         errno = EINVAL;
145         return -1;
146     }
147
148     if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
149         retval = 0;
150     else
151     {
152         retval = -1;
153         switch (GetLastError ())
154         {
155 #define CASE(a,b) case ERROR_##a: save_errno = b; break
156             CASE (FILE_NOT_FOUND, ENOENT);
157             CASE (PATH_NOT_FOUND, ENOENT);
158             CASE (ACCESS_DENIED, EACCES);
159             CASE (NOT_SAME_DEVICE, EXDEV);
160             CASE (LOCK_VIOLATION, EACCES);
161             CASE (SHARING_VIOLATION, EACCES);
162             CASE (FILE_EXISTS, EEXIST);
163             CASE (ALREADY_EXISTS, EEXIST);
164 #undef CASE
165             default: save_errno = EIO;
166         }
167     }
168
169     g_free (woldfilename);
170     g_free (wnewfilename);
171
172     errno = save_errno;
173     return retval;
174 }
175
176 /**
177  * g_mkdir:
178  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
179  * @mode: permissions to use for the newly created directory
180  *
181  * A wrapper for the POSIX mkdir() function. The mkdir() function
182  * attempts to create a directory with the given name and permissions.
183  *
184  * See the C library manual for more details about mkdir().
185  *
186  * Returns: 0 if the directory was successfully created, -1 if an error
187  *    occurred
188  *
189  * Since: 2.6
190  */
191 int
192 ws_stdio_mkdir (const gchar *filename, int mode)
193 {
194     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
195     int retval;
196     int save_errno;
197
198     if (wfilename == NULL)
199     {
200         errno = EINVAL;
201         return -1;
202     }
203
204     retval = _wmkdir (wfilename);
205     save_errno = errno;
206
207     g_free (wfilename);
208
209     errno = save_errno;
210     return retval;
211 }
212
213 /**
214  * g_stat:
215  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
216  * @buf: a pointer to a <structname>stat</structname> struct, which
217  *    will be filled with the file information
218  *
219  * A wrapper for the POSIX stat() function. The stat() function
220  * returns information about a file.
221  *
222  * See the C library manual for more details about stat().
223  *
224  * Returns: 0 if the information was successfully retrieved, -1 if an error
225  *    occurred
226  *
227  * Since: 2.6
228  */
229 int
230 ws_stdio_stat64 (const gchar *filename, ws_statb64 *buf)
231 {
232     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
233     int retval;
234     int save_errno;
235     size_t len;
236
237     if (wfilename == NULL)
238     {
239         errno = EINVAL;
240         return -1;
241     }
242
243     len = wcslen (wfilename);
244     while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
245         len--;
246     if (len > 0 &&
247             (!g_path_is_absolute (filename) || len > (size_t) (g_path_skip_root (filename) - filename)))
248         wfilename[len] = '\0';
249
250     retval = _wstati64 (wfilename, buf);
251     save_errno = errno;
252
253     g_free (wfilename);
254
255     errno = save_errno;
256     return retval;
257 }
258 /**
259  * g_unlink:
260  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
261  *
262  * A wrapper for the POSIX unlink() function. The unlink() function
263  * deletes a name from the filesystem. If this was the last link to the
264  * file and no processes have it opened, the diskspace occupied by the
265  * file is freed.
266  *
267  * See your C library manual for more details about unlink(). Note
268  * that on Windows, it is in general not possible to delete files that
269  * are open to some process, or mapped into memory.
270  *
271  * Returns: 0 if the name was successfully deleted, -1 if an error
272  *    occurred
273  *
274  * Since: 2.6
275  */
276
277 int
278 ws_stdio_unlink (const gchar *filename)
279 {
280     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
281     int retval;
282     int save_errno;
283
284     if (wfilename == NULL)
285     {
286         errno = EINVAL;
287         return -1;
288     }
289
290     retval = _wunlink (wfilename);
291     save_errno = errno;
292
293     g_free (wfilename);
294
295     errno = save_errno;
296     return retval;
297 }
298
299 /**
300  * g_remove:
301  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
302  *
303  * A wrapper for the POSIX remove() function. The remove() function
304  * deletes a name from the filesystem.
305  *
306  * See your C library manual for more details about how remove() works
307  * on your system. On Unix, remove() removes also directories, as it
308  * calls unlink() for files and rmdir() for directories. On Windows,
309  * although remove() in the C library only works for files, this
310  * function tries first remove() and then if that fails rmdir(), and
311  * thus works for both files and directories. Note however, that on
312  * Windows, it is in general not possible to remove a file that is
313  * open to some process, or mapped into memory.
314  *
315  * If this function fails on Windows you can't infer too much from the
316  * errno value. rmdir() is tried regardless of what caused remove() to
317  * fail. Any errno value set by remove() will be overwritten by that
318  * set by rmdir().
319  *
320  * Returns: 0 if the file was successfully removed, -1 if an error
321  *    occurred
322  *
323  * Since: 2.6
324  */
325 int
326 ws_stdio_remove (const gchar *filename)
327 {
328     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
329     int retval;
330     int save_errno;
331
332     if (wfilename == NULL)
333     {
334         errno = EINVAL;
335         return -1;
336     }
337
338     retval = _wremove (wfilename);
339     if (retval == -1)
340         retval = _wrmdir (wfilename);
341     save_errno = errno;
342
343     g_free (wfilename);
344
345     errno = save_errno;
346     return retval;
347 }
348
349 /**
350  * g_fopen:
351  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
352  * @mode: a string describing the mode in which the file should be
353  *   opened
354  *
355  * A wrapper for the POSIX fopen() function. The fopen() function opens
356  * a file and associates a new stream with it.
357  *
358  * See the C library manual for more details about fopen().
359  *
360  * Returns: A <type>FILE</type> pointer if the file was successfully
361  *    opened, or %NULL if an error occurred
362  *
363  * Since: 2.6
364  */
365 FILE *
366 ws_stdio_fopen (const gchar *filename, const gchar *mode)
367 {
368     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
369     wchar_t *wmode;
370     FILE *retval;
371     int save_errno;
372
373     if (wfilename == NULL)
374     {
375         errno = EINVAL;
376         return NULL;
377     }
378
379     wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
380
381     if (wmode == NULL)
382     {
383         g_free (wfilename);
384         errno = EINVAL;
385         return NULL;
386     }
387
388     retval = _wfopen (wfilename, wmode);
389     save_errno = errno;
390
391     g_free (wfilename);
392     g_free (wmode);
393
394     errno = save_errno;
395     return retval;
396 }
397
398 /**
399  * g_freopen:
400  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
401  * @mode: a string describing the mode in which the file should be
402  *   opened
403  * @stream: an existing stream which will be reused, or %NULL
404  *
405  * A wrapper for the POSIX freopen() function. The freopen() function
406  * opens a file and associates it with an existing stream.
407  *
408  * See the C library manual for more details about freopen().
409  *
410  * Returns: A <type>FILE</type> pointer if the file was successfully
411  *    opened, or %NULL if an error occurred.
412  *
413  * Since: 2.6
414  */
415 FILE *
416 ws_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream)
417 {
418     wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
419     wchar_t *wmode;
420     FILE *retval;
421     int save_errno;
422
423     if (wfilename == NULL)
424     {
425         errno = EINVAL;
426         return NULL;
427     }
428
429     wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
430
431     if (wmode == NULL)
432     {
433         g_free (wfilename);
434         errno = EINVAL;
435         return NULL;
436     }
437
438     retval = _wfreopen (wfilename, wmode, stream);
439     save_errno = errno;
440
441     g_free (wfilename);
442     g_free (wmode);
443
444     errno = save_errno;
445     return retval;
446 }
447
448
449 /* DLL loading */
450 static gboolean
451 init_dll_load_paths()
452 {
453     TCHAR path_w[MAX_PATH];
454
455     if (program_path && system_path && npcap_path)
456         return TRUE;
457
458     /* XXX - Duplicate code in filesystem.c:init_progfile_dir */
459     if (GetModuleFileName(NULL, path_w, MAX_PATH) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
460         return FALSE;
461     }
462
463     if (!program_path) {
464         gchar *app_path;
465         app_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
466         /* We could use PathRemoveFileSpec here but we'd have to link to Shlwapi.dll */
467         program_path = g_path_get_dirname(app_path);
468         g_free(app_path);
469     }
470
471     if (GetSystemDirectory(path_w, MAX_PATH) == 0) {
472         return FALSE;
473     }
474
475     if (!system_path) {
476         system_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
477     }
478
479     _tcscat_s(path_w, MAX_PATH, _T("\\Npcap"));
480
481     if (!npcap_path) {
482         npcap_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
483     }
484
485     if (program_path && system_path && npcap_path)
486         return TRUE;
487
488     return FALSE;
489 }
490
491 gboolean
492 ws_init_dll_search_path()
493 {
494     gboolean dll_dir_set = FALSE;
495     wchar_t *program_path_w;
496
497     /* Remove the current directory from the default DLL search path. */
498     SetDllDirectory(_T(""));
499
500     if (init_dll_load_paths()) {
501         /* Ensure that extcap executables can find wsutil, etc. */
502         program_path_w = g_utf8_to_utf16(program_path, -1, NULL, NULL, NULL);
503         dll_dir_set = SetDllDirectory(program_path_w);
504         g_free(program_path_w);
505     }
506
507     return dll_dir_set;
508 }
509
510 /*
511  * Internally g_module_open uses LoadLibrary on Windows and returns an
512  * HMODULE cast to a GModule *. However there's no guarantee that this
513  * will always be the case, so we call LoadLibrary and g_module_open
514  * separately.
515  */
516
517 void *
518 ws_load_library(const gchar *library_name)
519 {
520     gchar   *full_path;
521     wchar_t *full_path_w;
522     HMODULE  dll_h;
523
524     if (!init_dll_load_paths() || !library_name)
525         return NULL;
526
527     /* First try the program directory */
528     full_path = g_module_build_path(program_path, library_name);
529     full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
530
531     if (full_path && full_path_w) {
532         dll_h = LoadLibraryW(full_path_w);
533         if (dll_h) {
534             g_free(full_path);
535             g_free(full_path_w);
536             return dll_h;
537         }
538     }
539
540     /* Next try the system directory */
541     full_path = g_module_build_path(system_path, library_name);
542     full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
543
544     if (full_path && full_path_w) {
545         dll_h = LoadLibraryW(full_path_w);
546         if (dll_h) {
547             g_free(full_path);
548             g_free(full_path_w);
549             return dll_h;
550         }
551     }
552
553     return NULL;
554 }
555
556 static GModule *
557 load_npcap_module(const gchar *full_path, GModuleFlags flags)
558 {
559     /*
560      * Npcap's wpcap.dll requires packet.dll from the same directory. Either
561      * SetDllDirectory or SetCurrentDirectory could make this work, but it
562      * interferes with other uses of these settings. LoadLibraryEx is ideal as
563      * it can be configured to put the directory containing the DLL to the
564      * search path. Unfortunately g_module_open uses LoadLibrary internally, so
565      * as a workaround manually load the Npcap libraries first and then use
566      * g_module_open to obtain a GModule for the loaded library.
567      */
568
569     wchar_t *wpath = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
570     HMODULE module = LoadLibraryEx(wpath, NULL, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR);
571     g_free(wpath);
572     if (!module) {
573         return NULL;
574     }
575     GModule *mod = g_module_open(full_path, flags);
576     FreeLibrary(module);
577     return mod;
578 }
579
580 GModule *
581 ws_module_open(gchar *module_name, GModuleFlags flags)
582 {
583     gchar   *full_path;
584     GModule *mod;
585
586     if (!init_dll_load_paths() || !module_name)
587         return NULL;
588
589     /* First try the program directory */
590     full_path = g_module_build_path(program_path, module_name);
591
592     if (full_path) {
593         mod = g_module_open(full_path, flags);
594         g_free(full_path);
595         if (mod) {
596             return mod;
597         }
598     }
599
600     /* Next try the Npcap directory */
601     full_path = g_module_build_path(npcap_path, module_name);
602
603     if (full_path) {
604         mod = load_npcap_module(full_path, flags);
605         g_free(full_path);
606         if (mod) {
607             return mod;
608         }
609     }
610
611     /* At last try the system directory */
612     full_path = g_module_build_path(system_path, module_name);
613
614     if (full_path) {
615         mod = g_module_open(full_path, flags);
616         g_free(full_path);
617         if (mod) {
618             return mod;
619         }
620     }
621
622     return NULL;
623 }
624
625 /** Create or open a "Wireshark is running" mutex.
626  */
627 #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B"
628
629 static SECURITY_ATTRIBUTES *sec_attributes_;
630
631 static HANDLE local_running_mutex = NULL;
632 static HANDLE global_running_mutex = NULL;
633
634 void create_app_running_mutex() {
635     SECURITY_ATTRIBUTES *sa = NULL;
636
637     if (!sec_attributes_) sec_attributes_ = g_new0(SECURITY_ATTRIBUTES, 1);
638
639     sec_attributes_->nLength = sizeof(SECURITY_ATTRIBUTES);
640     sec_attributes_->lpSecurityDescriptor = g_new0(SECURITY_DESCRIPTOR, 1);
641     sec_attributes_->bInheritHandle = TRUE;
642     if (InitializeSecurityDescriptor(sec_attributes_->lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) {
643         if (SetSecurityDescriptorDacl(sec_attributes_->lpSecurityDescriptor, TRUE, NULL, FALSE)) {
644             sa = sec_attributes_;
645         }
646     }
647
648     if (!sa) {
649         g_free(sec_attributes_->lpSecurityDescriptor);
650         g_free(sec_attributes_);
651         sec_attributes_ = NULL;
652     }
653     local_running_mutex = CreateMutex(sa, FALSE, _T("Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
654     global_running_mutex = CreateMutex(sa, FALSE, _T("Global\\Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
655 }
656
657 void close_app_running_mutex() {
658     if (local_running_mutex) {
659         CloseHandle(local_running_mutex);
660         local_running_mutex = NULL;
661     }
662     if (global_running_mutex) {
663         CloseHandle(global_running_mutex);
664         global_running_mutex = NULL;
665     }
666 }
667
668 /*
669  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
670  *
671  * Local Variables:
672  * c-basic-offset: 4
673  * tab-width: 8
674  * indent-tabs-mode: nil
675  * End:
676  *
677  * ex: set shiftwidth=4 tabstop=8 expandtab:
678  * :indentSize=4:tabSize=8:noTabs=true:
679  */