3 * (Originally part of the Wiretap Library, now part of the Wireshark
5 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7 * SPDX-License-Identifier: GPL-2.0-or-later
11 * File wrapper functions to replace the file functions from GLib like
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.
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
22 * (If both were built to use the Universal CRT:
24 * http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx
26 * this would not be a problem.)
28 * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS
29 * FROM file_util.h INSTEAD!!!
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.
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.
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?
46 #error "This is only for Windows"
60 #include "file_util.h"
61 #include "ws_attributes.h"
63 static char *program_path
;
64 static char *system_path
;
65 static char *npcap_path
;
69 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
70 * @flags: as in open()
73 * A wrapper for the POSIX open() function. The open() function is
74 * used to convert a pathname into a file descriptor. Note that on
75 * POSIX systems file descriptors are implemented by the operating
76 * system. On Windows, it's the C library that implements open() and
77 * file descriptors. The actual Windows API for opening files is
78 * something different.
80 * See the C library manual for more details about open().
82 * Returns: a new file descriptor, or -1 if an error occurred. The
83 * return value can be used exactly like the return value from open().
88 ws_stdio_open (const char *filename
, int flags
, int mode
)
90 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
94 if (wfilename
== NULL
)
100 retval
= _wopen (wfilename
, flags
, mode
);
112 * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
113 * @newfilename: a pathname in the GLib file name encoding
115 * A wrapper for the POSIX rename() function. The rename() function
116 * renames a file, moving it between directories if required.
118 * See your C library manual for more details about how rename() works
119 * on your system. Note in particular that on Win9x it is not possible
120 * to rename a file if a file with the new name already exists. Also
121 * it is not possible in general on Windows to rename an open file.
123 * Returns: 0 if the renaming succeeded, -1 if an error occurred
128 ws_stdio_rename (const char *oldfilename
, const char *newfilename
)
130 wchar_t *woldfilename
= g_utf8_to_utf16 (oldfilename
, -1, NULL
, NULL
, NULL
);
131 wchar_t *wnewfilename
;
135 if (woldfilename
== NULL
)
141 wnewfilename
= g_utf8_to_utf16 (newfilename
, -1, NULL
, NULL
, NULL
);
143 if (wnewfilename
== NULL
)
145 g_free (woldfilename
);
150 if (MoveFileExW (woldfilename
, wnewfilename
, MOVEFILE_REPLACE_EXISTING
))
155 switch (GetLastError ())
157 #define CASE(a,b) case ERROR_##a: save_errno = b; break
158 CASE (FILE_NOT_FOUND
, ENOENT
);
159 CASE (PATH_NOT_FOUND
, ENOENT
);
160 CASE (ACCESS_DENIED
, EACCES
);
161 CASE (NOT_SAME_DEVICE
, EXDEV
);
162 CASE (LOCK_VIOLATION
, EACCES
);
163 CASE (SHARING_VIOLATION
, EACCES
);
164 CASE (FILE_EXISTS
, EEXIST
);
165 CASE (ALREADY_EXISTS
, EEXIST
);
167 default: save_errno
= EIO
;
171 g_free (woldfilename
);
172 g_free (wnewfilename
);
180 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
181 * @mode: permissions to use for the newly created directory
183 * A wrapper for the POSIX mkdir() function. The mkdir() function
184 * attempts to create a directory with the given name and permissions.
186 * See the C library manual for more details about mkdir().
188 * Returns: 0 if the directory was successfully created, -1 if an error
194 ws_stdio_mkdir (const char *filename
, int mode _U_
)
196 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
200 if (wfilename
== NULL
)
206 retval
= _wmkdir (wfilename
);
217 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
218 * @buf: a pointer to a <structname>stat</structname> struct, which
219 * will be filled with the file information
221 * A wrapper for the POSIX stat() function. The stat() function
222 * returns information about a file.
224 * See the C library manual for more details about stat().
226 * Returns: 0 if the information was successfully retrieved, -1 if an error
232 ws_stdio_stat64 (const char *filename
, ws_statb64
*buf
)
234 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
239 if (wfilename
== NULL
)
245 len
= wcslen (wfilename
);
246 while (len
> 0 && G_IS_DIR_SEPARATOR (wfilename
[len
-1]))
249 (!g_path_is_absolute (filename
) || len
> (size_t) (g_path_skip_root (filename
) - filename
)))
250 wfilename
[len
] = '\0';
252 retval
= _wstati64 (wfilename
, buf
);
262 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
264 * A wrapper for the POSIX unlink() function. The unlink() function
265 * deletes a name from the filesystem. If this was the last link to the
266 * file and no processes have it opened, the diskspace occupied by the
269 * See your C library manual for more details about unlink(). Note
270 * that on Windows, it is in general not possible to delete files that
271 * are open to some process, or mapped into memory.
273 * Returns: 0 if the name was successfully deleted, -1 if an error
280 ws_stdio_unlink (const char *filename
)
282 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
286 if (wfilename
== NULL
)
292 retval
= _wunlink (wfilename
);
303 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
305 * A wrapper for the POSIX remove() function. The remove() function
306 * deletes a name from the filesystem.
308 * See your C library manual for more details about how remove() works
309 * on your system. On Unix, remove() removes also directories, as it
310 * calls unlink() for files and rmdir() for directories. On Windows,
311 * although remove() in the C library only works for files, this
312 * function tries first remove() and then if that fails rmdir(), and
313 * thus works for both files and directories. Note however, that on
314 * Windows, it is in general not possible to remove a file that is
315 * open to some process, or mapped into memory.
317 * If this function fails on Windows you can't infer too much from the
318 * errno value. rmdir() is tried regardless of what caused remove() to
319 * fail. Any errno value set by remove() will be overwritten by that
322 * Returns: 0 if the file was successfully removed, -1 if an error
328 ws_stdio_remove (const char *filename
)
330 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
334 if (wfilename
== NULL
)
340 retval
= _wremove (wfilename
);
342 retval
= _wrmdir (wfilename
);
353 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
354 * @mode: a string describing the mode in which the file should be
357 * A wrapper for the POSIX fopen() function. The fopen() function opens
358 * a file and associates a new stream with it.
360 * See the C library manual for more details about fopen().
362 * Returns: A <type>FILE</type> pointer if the file was successfully
363 * opened, or %NULL if an error occurred
368 ws_stdio_fopen (const char *filename
, const char *mode
)
370 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
375 if (wfilename
== NULL
)
381 wmode
= g_utf8_to_utf16 (mode
, -1, NULL
, NULL
, NULL
);
390 retval
= _wfopen (wfilename
, wmode
);
402 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
403 * @mode: a string describing the mode in which the file should be
405 * @stream: an existing stream which will be reused, or %NULL
407 * A wrapper for the POSIX freopen() function. The freopen() function
408 * opens a file and associates it with an existing stream.
410 * See the C library manual for more details about freopen().
412 * Returns: A <type>FILE</type> pointer if the file was successfully
413 * opened, or %NULL if an error occurred.
418 ws_stdio_freopen (const char *filename
, const char *mode
, FILE *stream
)
420 wchar_t *wfilename
= g_utf8_to_utf16 (filename
, -1, NULL
, NULL
, NULL
);
425 if (wfilename
== NULL
)
431 wmode
= g_utf8_to_utf16 (mode
, -1, NULL
, NULL
, NULL
);
440 retval
= _wfreopen (wfilename
, wmode
, stream
);
453 init_dll_load_paths(void)
455 TCHAR path_w
[MAX_PATH
];
457 if (program_path
&& system_path
&& npcap_path
)
460 /* XXX - Duplicate code in filesystem.c:configuration_init */
461 if (GetModuleFileName(NULL
, path_w
, MAX_PATH
) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER
) {
467 app_path
= g_utf16_to_utf8(path_w
, -1, NULL
, NULL
, NULL
);
468 /* We could use PathRemoveFileSpec here but we'd have to link to Shlwapi.dll */
469 program_path
= g_path_get_dirname(app_path
);
473 if (GetSystemDirectory(path_w
, MAX_PATH
) == 0) {
478 system_path
= g_utf16_to_utf8(path_w
, -1, NULL
, NULL
, NULL
);
481 _tcscat_s(path_w
, MAX_PATH
, _T("\\Npcap"));
484 npcap_path
= g_utf16_to_utf8(path_w
, -1, NULL
, NULL
, NULL
);
487 if (program_path
&& system_path
&& npcap_path
)
494 ws_init_dll_search_path(void)
496 bool dll_dir_set
= false;
497 wchar_t *program_path_w
;
499 /* Remove the current directory from the default DLL search path. */
500 SetDllDirectory(_T(""));
502 if (init_dll_load_paths()) {
503 /* Ensure that extcap executables can find wsutil, etc. */
504 program_path_w
= g_utf8_to_utf16(program_path
, -1, NULL
, NULL
, NULL
);
505 dll_dir_set
= SetDllDirectory(program_path_w
);
506 g_free(program_path_w
);
513 * Internally g_module_open uses LoadLibrary on Windows and returns an
514 * HMODULE cast to a GModule *. However there's no guarantee that this
515 * will always be the case, so we call LoadLibrary and g_module_open
520 ws_load_library(const char *library_name
)
523 wchar_t *full_path_w
;
526 if (!init_dll_load_paths() || !library_name
)
529 /* First try the program directory */
530 full_path
= g_strconcat(program_path
, G_DIR_SEPARATOR_S
, library_name
, NULL
);
531 full_path_w
= g_utf8_to_utf16(full_path
, -1, NULL
, NULL
, NULL
);
533 if (full_path
&& full_path_w
) {
534 dll_h
= LoadLibraryW(full_path_w
);
542 /* Next try the system directory */
543 full_path
= g_strconcat(system_path
, G_DIR_SEPARATOR_S
, library_name
, NULL
);
544 full_path_w
= g_utf8_to_utf16(full_path
, -1, NULL
, NULL
, NULL
);
546 if (full_path
&& full_path_w
) {
547 dll_h
= LoadLibraryW(full_path_w
);
559 load_npcap_module(const char *full_path
, GModuleFlags flags
)
562 * Npcap's wpcap.dll requires packet.dll from the same directory. Either
563 * SetDllDirectory or SetCurrentDirectory could make this work, but it
564 * interferes with other uses of these settings. LoadLibraryEx is ideal as
565 * it can be configured to put the directory containing the DLL to the
566 * search path. Unfortunately g_module_open uses LoadLibrary internally, so
567 * as a workaround manually load the Npcap libraries first and then use
568 * g_module_open to obtain a GModule for the loaded library.
571 wchar_t *wpath
= g_utf8_to_utf16(full_path
, -1, NULL
, NULL
, NULL
);
572 HMODULE module
= LoadLibraryEx(wpath
, NULL
, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS
| LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
);
577 GModule
*mod
= g_module_open(full_path
, flags
);
583 load_wpcap_module(void)
585 char *module_name
= "wpcap.dll";
588 GModuleFlags flags
= 0;
590 if (!init_dll_load_paths())
593 /* First try the program directory */
594 full_path
= g_strconcat(program_path
, G_DIR_SEPARATOR_S
, module_name
, NULL
);
597 mod
= g_module_open(full_path
, flags
);
604 /* Next try the Npcap directory */
605 full_path
= g_strconcat(npcap_path
, G_DIR_SEPARATOR_S
, module_name
, NULL
);
608 mod
= load_npcap_module(full_path
, flags
);
615 /* At last try the system directory */
616 full_path
= g_strconcat(system_path
, G_DIR_SEPARATOR_S
, module_name
, NULL
);
619 mod
= g_module_open(full_path
, flags
);
629 /** Create or open a "Wireshark is running" mutex.
631 #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B"
633 static HANDLE local_running_mutex
;
634 static HANDLE global_running_mutex
;
636 void create_app_running_mutex(void) {
637 SECURITY_DESCRIPTOR sec_descriptor
;
638 SECURITY_ATTRIBUTES sec_attributes
;
639 SECURITY_ATTRIBUTES
*sa
;
640 memset(&sec_descriptor
, 0, sizeof(SECURITY_DESCRIPTOR
));
641 if (!InitializeSecurityDescriptor(&sec_descriptor
, SECURITY_DESCRIPTOR_REVISION
) ||
642 !SetSecurityDescriptorDacl(&sec_descriptor
, true, NULL
, false)) {
644 * We couldn't set up the security descriptor, so use the default
645 * security attributes when creating the mutexes.
650 * We could set it up, so set up some attributes that refer
653 memset(&sec_attributes
, 0, sizeof(SECURITY_ATTRIBUTES
));
654 sec_attributes
.nLength
= sizeof(SECURITY_ATTRIBUTES
);
655 sec_attributes
.lpSecurityDescriptor
= &sec_descriptor
;
656 sec_attributes
.bInheritHandle
= true;
657 sa
= &sec_attributes
;
659 local_running_mutex
= CreateMutex(sa
, false, _T("Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID
) _T("}"));
660 global_running_mutex
= CreateMutex(sa
, false, _T("Global\\Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID
) _T("}"));
663 void close_app_running_mutex(void) {
664 if (local_running_mutex
) {
665 CloseHandle(local_running_mutex
);
666 local_running_mutex
= NULL
;
668 if (global_running_mutex
) {
669 CloseHandle(global_running_mutex
);
670 global_running_mutex
= NULL
;
674 int ws_close_if_possible(int fd
) {
676 struct timeval tv
= { 0, 1 };
682 retval
= select(1, &rfds
, NULL
, NULL
, &tv
);
690 * Editor modelines - https://www.wireshark.org/tools/modelines.html
695 * indent-tabs-mode: nil
698 * ex: set shiftwidth=4 tabstop=8 expandtab:
699 * :indentSize=4:tabSize=8:noTabs=true: