3 * (Originally part of the Wiretap Library, now part of the Wireshark
5 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * File wrapper functions to replace the file functions from GLib like
27 * With MSVC, code using the C support library from one version of MSVC
28 * cannot use file descriptors or FILE *'s returned from code using
29 * the C support library from another version of MSVC.
31 * We therefore provide our own versions of the routines to open files,
32 * so that they're built to use the same C support library as our code
35 * (If both were built to use the Universal CRT:
37 * http://blogs.msdn.com/b/vcblog/archive/2015/03/03/introducing-the-universal-crt.aspx
39 * this would not be a problem.)
41 * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS
42 * FROM file_util.h INSTEAD!!!
44 * The following code is stripped down code copied from the GLib file
45 * glib/gstdio.h - stripped down because this is used only on Windows
46 * and we use only wide char functions.
48 * In addition, we have our own ws_stdio_stat64(), which uses
49 * _wstati64(), so that we can get file sizes for files > 4 GB in size.
51 * XXX - is there any reason why we supply our own versions of routines
52 * that *don't* return file descriptors, other than ws_stdio_stat64()?
53 * Is there an issue with UTF-16 support in _wmkdir() with some versions
54 * of the C runtime, so that if GLib is built to use that version, it
55 * won't handle UTF-16 paths?
59 #error "This is only for Windows"
72 #include "file_util.h"
74 static gchar *program_path = NULL;
75 static gchar *system_path = NULL;
76 static gchar *npcap_path = NULL;
80 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
81 * @flags: as in open()
84 * A wrapper for the POSIX open() function. The open() function is
85 * used to convert a pathname into a file descriptor. Note that on
86 * POSIX systems file descriptors are implemented by the operating
87 * system. On Windows, it's the C library that implements open() and
88 * file descriptors. The actual Windows API for opening files is
89 * something different.
91 * See the C library manual for more details about open().
93 * Returns: a new file descriptor, or -1 if an error occurred. The
94 * return value can be used exactly like the return value from open().
99 ws_stdio_open (const gchar *filename, int flags, int mode)
101 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
105 if (wfilename == NULL)
111 retval = _wopen (wfilename, flags, mode);
123 * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
124 * @newfilename: a pathname in the GLib file name encoding
126 * A wrapper for the POSIX rename() function. The rename() function
127 * renames a file, moving it between directories if required.
129 * See your C library manual for more details about how rename() works
130 * on your system. Note in particular that on Win9x it is not possible
131 * to rename a file if a file with the new name already exists. Also
132 * it is not possible in general on Windows to rename an open file.
134 * Returns: 0 if the renaming succeeded, -1 if an error occurred
139 ws_stdio_rename (const gchar *oldfilename, const gchar *newfilename)
141 wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
142 wchar_t *wnewfilename;
146 if (woldfilename == NULL)
152 wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
154 if (wnewfilename == NULL)
156 g_free (woldfilename);
161 if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
166 switch (GetLastError ())
168 #define CASE(a,b) case ERROR_##a: save_errno = b; break
169 CASE (FILE_NOT_FOUND, ENOENT);
170 CASE (PATH_NOT_FOUND, ENOENT);
171 CASE (ACCESS_DENIED, EACCES);
172 CASE (NOT_SAME_DEVICE, EXDEV);
173 CASE (LOCK_VIOLATION, EACCES);
174 CASE (SHARING_VIOLATION, EACCES);
175 CASE (FILE_EXISTS, EEXIST);
176 CASE (ALREADY_EXISTS, EEXIST);
178 default: save_errno = EIO;
182 g_free (woldfilename);
183 g_free (wnewfilename);
191 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
192 * @mode: permissions to use for the newly created directory
194 * A wrapper for the POSIX mkdir() function. The mkdir() function
195 * attempts to create a directory with the given name and permissions.
197 * See the C library manual for more details about mkdir().
199 * Returns: 0 if the directory was successfully created, -1 if an error
205 ws_stdio_mkdir (const gchar *filename, int mode)
207 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
211 if (wfilename == NULL)
217 retval = _wmkdir (wfilename);
228 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
229 * @buf: a pointer to a <structname>stat</structname> struct, which
230 * will be filled with the file information
232 * A wrapper for the POSIX stat() function. The stat() function
233 * returns information about a file.
235 * See the C library manual for more details about stat().
237 * Returns: 0 if the information was successfully retrieved, -1 if an error
243 ws_stdio_stat64 (const gchar *filename, ws_statb64 *buf)
245 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
250 if (wfilename == NULL)
256 len = wcslen (wfilename);
257 while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
260 (!g_path_is_absolute (filename) || len > (size_t) (g_path_skip_root (filename) - filename)))
261 wfilename[len] = '\0';
263 retval = _wstati64 (wfilename, buf);
273 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
275 * A wrapper for the POSIX unlink() function. The unlink() function
276 * deletes a name from the filesystem. If this was the last link to the
277 * file and no processes have it opened, the diskspace occupied by the
280 * See your C library manual for more details about unlink(). Note
281 * that on Windows, it is in general not possible to delete files that
282 * are open to some process, or mapped into memory.
284 * Returns: 0 if the name was successfully deleted, -1 if an error
291 ws_stdio_unlink (const gchar *filename)
293 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
297 if (wfilename == NULL)
303 retval = _wunlink (wfilename);
314 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
316 * A wrapper for the POSIX remove() function. The remove() function
317 * deletes a name from the filesystem.
319 * See your C library manual for more details about how remove() works
320 * on your system. On Unix, remove() removes also directories, as it
321 * calls unlink() for files and rmdir() for directories. On Windows,
322 * although remove() in the C library only works for files, this
323 * function tries first remove() and then if that fails rmdir(), and
324 * thus works for both files and directories. Note however, that on
325 * Windows, it is in general not possible to remove a file that is
326 * open to some process, or mapped into memory.
328 * If this function fails on Windows you can't infer too much from the
329 * errno value. rmdir() is tried regardless of what caused remove() to
330 * fail. Any errno value set by remove() will be overwritten by that
333 * Returns: 0 if the file was successfully removed, -1 if an error
339 ws_stdio_remove (const gchar *filename)
341 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
345 if (wfilename == NULL)
351 retval = _wremove (wfilename);
353 retval = _wrmdir (wfilename);
364 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
365 * @mode: a string describing the mode in which the file should be
368 * A wrapper for the POSIX fopen() function. The fopen() function opens
369 * a file and associates a new stream with it.
371 * See the C library manual for more details about fopen().
373 * Returns: A <type>FILE</type> pointer if the file was successfully
374 * opened, or %NULL if an error occurred
379 ws_stdio_fopen (const gchar *filename, const gchar *mode)
381 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
386 if (wfilename == NULL)
392 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
401 retval = _wfopen (wfilename, wmode);
413 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
414 * @mode: a string describing the mode in which the file should be
416 * @stream: an existing stream which will be reused, or %NULL
418 * A wrapper for the POSIX freopen() function. The freopen() function
419 * opens a file and associates it with an existing stream.
421 * See the C library manual for more details about freopen().
423 * Returns: A <type>FILE</type> pointer if the file was successfully
424 * opened, or %NULL if an error occurred.
429 ws_stdio_freopen (const gchar *filename, const gchar *mode, FILE *stream)
431 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
436 if (wfilename == NULL)
442 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
451 retval = _wfreopen (wfilename, wmode, stream);
464 init_dll_load_paths()
466 TCHAR path_w[MAX_PATH];
468 if (program_path && system_path && npcap_path)
471 /* XXX - Duplicate code in filesystem.c:init_progfile_dir */
472 if (GetModuleFileName(NULL, path_w, MAX_PATH) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
478 app_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
479 /* We could use PathRemoveFileSpec here but we'd have to link to Shlwapi.dll */
480 program_path = g_path_get_dirname(app_path);
484 if (GetSystemDirectory(path_w, MAX_PATH) == 0) {
489 system_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
492 _tcscat_s(path_w, MAX_PATH, _T("\\Npcap"));
495 npcap_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
498 if (program_path && system_path && npcap_path)
505 ws_init_dll_search_path()
507 gboolean dll_dir_set = FALSE, npf_found = FALSE;
508 wchar_t *program_path_w;
509 wchar_t npcap_path_w[MAX_PATH];
513 typedef BOOL (WINAPI *SetDllDirectoryHandler)(LPCTSTR);
514 SetDllDirectoryHandler PSetDllDirectory;
516 PSetDllDirectory = (SetDllDirectoryHandler) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "SetDllDirectoryW");
517 if (PSetDllDirectory) {
518 dll_dir_set = PSetDllDirectory(_T(""));
520 /* Do not systematically add Npcap path as long as we favor WinPcap over Npcap. */
521 h_scm = OpenSCManager(NULL, NULL, 0);
523 if (OpenService(h_scm, _T("npf"), SC_MANAGER_CONNECT|SERVICE_QUERY_STATUS)) {
526 CloseServiceHandle(h_scm);
529 /* npf service was not found, so WinPcap is not (properly) installed.
530 Add Npcap folder to libraries search path. */
531 retval = GetSystemDirectoryW(npcap_path_w, MAX_PATH);
532 if (0 < retval && retval <= MAX_PATH) {
533 wcscat_s(npcap_path_w, MAX_PATH, L"\\Npcap");
534 dll_dir_set = PSetDllDirectory(npcap_path_w);
540 if (!dll_dir_set && init_dll_load_paths()) {
541 program_path_w = g_utf8_to_utf16(program_path, -1, NULL, NULL, NULL);
542 SetCurrentDirectory(program_path_w);
543 g_free(program_path_w);
550 * Internally g_module_open uses LoadLibrary on Windows and returns an
551 * HMODULE cast to a GModule *. However there's no guarantee that this
552 * will always be the case, so we call LoadLibrary and g_module_open
557 ws_load_library(const gchar *library_name)
560 wchar_t *full_path_w;
563 if (!init_dll_load_paths() || !library_name)
566 /* First try the program directory */
567 full_path = g_module_build_path(program_path, library_name);
568 full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
570 if (full_path && full_path_w) {
571 dll_h = LoadLibraryW(full_path_w);
579 /* Next try the system directory */
580 full_path = g_module_build_path(system_path, library_name);
581 full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
583 if (full_path && full_path_w) {
584 dll_h = LoadLibraryW(full_path_w);
596 ws_module_open(gchar *module_name, GModuleFlags flags)
601 if (!init_dll_load_paths() || !module_name)
604 /* First try the program directory */
605 full_path = g_module_build_path(program_path, module_name);
608 mod = g_module_open(full_path, flags);
615 /* Next try the system directory */
616 full_path = g_module_build_path(system_path, module_name);
619 mod = g_module_open(full_path, flags);
626 /* At last try the Npcap directory */
627 full_path = g_module_build_path(npcap_path, module_name);
630 mod = g_module_open(full_path, flags);
640 /** Create or open a "Wireshark is running" mutex.
642 #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B"
644 static SECURITY_ATTRIBUTES *sec_attributes_;
646 static HANDLE local_running_mutex = NULL;
647 static HANDLE global_running_mutex = NULL;
649 void create_app_running_mutex() {
650 SECURITY_ATTRIBUTES *sa = NULL;
652 if (!sec_attributes_) sec_attributes_ = g_new0(SECURITY_ATTRIBUTES, 1);
654 sec_attributes_->nLength = sizeof(SECURITY_ATTRIBUTES);
655 sec_attributes_->lpSecurityDescriptor = g_new0(SECURITY_DESCRIPTOR, 1);
656 sec_attributes_->bInheritHandle = TRUE;
657 if (InitializeSecurityDescriptor(sec_attributes_->lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) {
658 if (SetSecurityDescriptorDacl(sec_attributes_->lpSecurityDescriptor, TRUE, NULL, FALSE)) {
659 sa = sec_attributes_;
664 g_free(sec_attributes_->lpSecurityDescriptor);
665 g_free(sec_attributes_);
666 sec_attributes_ = NULL;
668 local_running_mutex = CreateMutex(sa, FALSE, _T("Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
669 global_running_mutex = CreateMutex(sa, FALSE, _T("Global\\Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
672 void close_app_running_mutex() {
673 if (local_running_mutex) {
674 CloseHandle(local_running_mutex);
675 local_running_mutex = NULL;
677 if (global_running_mutex) {
678 CloseHandle(global_running_mutex);
679 global_running_mutex = NULL;
684 * Editor modelines - http://www.wireshark.org/tools/modelines.html
689 * indent-tabs-mode: nil
692 * ex: set shiftwidth=4 tabstop=8 expandtab:
693 * :indentSize=4:tabSize=8:noTabs=true: