update epan/dissectors/pidl/drsuapi/drsuapi.idl from samba
[wireshark-sm.git] / wsutil / file_util.c
blobd36ae75fd932ba04d08738c38c13b28307092863
1 /* file_util.c
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>
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
11 * File wrapper functions to replace the file functions from GLib like
12 * g_open().
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
20 * that reads them.
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?
45 #ifndef _WIN32
46 #error "This is only for Windows"
47 #endif
49 #include "config.h"
51 #include <glib.h>
53 #include <windows.h>
54 #include <winsock2.h>
55 #include <errno.h>
56 #include <wchar.h>
57 #include <tchar.h>
58 #include <stdlib.h>
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;
67 /**
68 * g_open:
69 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
70 * @flags: as in open()
71 * @mode: 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().
85 * Since: 2.6
87 int
88 ws_stdio_open (const char *filename, int flags, int mode)
90 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
91 int retval;
92 int save_errno;
94 if (wfilename == NULL)
96 errno = EINVAL;
97 return -1;
100 retval = _wopen (wfilename, flags, mode);
101 save_errno = errno;
103 g_free (wfilename);
105 errno = save_errno;
106 return retval;
111 * g_rename:
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
125 * Since: 2.6
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;
132 int retval;
133 int save_errno = 0;
135 if (woldfilename == NULL)
137 errno = EINVAL;
138 return -1;
141 wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
143 if (wnewfilename == NULL)
145 g_free (woldfilename);
146 errno = EINVAL;
147 return -1;
150 if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
151 retval = 0;
152 else
154 retval = -1;
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);
166 #undef CASE
167 default: save_errno = EIO;
171 g_free (woldfilename);
172 g_free (wnewfilename);
174 errno = save_errno;
175 return retval;
179 * g_mkdir:
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
189 * occurred
191 * Since: 2.6
194 ws_stdio_mkdir (const char *filename, int mode _U_)
196 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
197 int retval;
198 int save_errno;
200 if (wfilename == NULL)
202 errno = EINVAL;
203 return -1;
206 retval = _wmkdir (wfilename);
207 save_errno = errno;
209 g_free (wfilename);
211 errno = save_errno;
212 return retval;
216 * g_stat:
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
227 * occurred
229 * Since: 2.6
232 ws_stdio_stat64 (const char *filename, ws_statb64 *buf)
234 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
235 int retval;
236 int save_errno;
237 size_t len;
239 if (wfilename == NULL)
241 errno = EINVAL;
242 return -1;
245 len = wcslen (wfilename);
246 while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
247 len--;
248 if (len > 0 &&
249 (!g_path_is_absolute (filename) || len > (size_t) (g_path_skip_root (filename) - filename)))
250 wfilename[len] = '\0';
252 retval = _wstati64 (wfilename, buf);
253 save_errno = errno;
255 g_free (wfilename);
257 errno = save_errno;
258 return retval;
261 * g_unlink:
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
267 * file is freed.
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
274 * occurred
276 * Since: 2.6
280 ws_stdio_unlink (const char *filename)
282 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
283 int retval;
284 int save_errno;
286 if (wfilename == NULL)
288 errno = EINVAL;
289 return -1;
292 retval = _wunlink (wfilename);
293 save_errno = errno;
295 g_free (wfilename);
297 errno = save_errno;
298 return retval;
302 * g_remove:
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
320 * set by rmdir().
322 * Returns: 0 if the file was successfully removed, -1 if an error
323 * occurred
325 * Since: 2.6
328 ws_stdio_remove (const char *filename)
330 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
331 int retval;
332 int save_errno;
334 if (wfilename == NULL)
336 errno = EINVAL;
337 return -1;
340 retval = _wremove (wfilename);
341 if (retval == -1)
342 retval = _wrmdir (wfilename);
343 save_errno = errno;
345 g_free (wfilename);
347 errno = save_errno;
348 return retval;
352 * g_fopen:
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
355 * opened
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
365 * Since: 2.6
367 FILE *
368 ws_stdio_fopen (const char *filename, const char *mode)
370 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
371 wchar_t *wmode;
372 FILE *retval;
373 int save_errno;
375 if (wfilename == NULL)
377 errno = EINVAL;
378 return NULL;
381 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
383 if (wmode == NULL)
385 g_free (wfilename);
386 errno = EINVAL;
387 return NULL;
390 retval = _wfopen (wfilename, wmode);
391 save_errno = errno;
393 g_free (wfilename);
394 g_free (wmode);
396 errno = save_errno;
397 return retval;
401 * g_freopen:
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
404 * opened
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.
415 * Since: 2.6
417 FILE *
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);
421 wchar_t *wmode;
422 FILE *retval;
423 int save_errno;
425 if (wfilename == NULL)
427 errno = EINVAL;
428 return NULL;
431 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
433 if (wmode == NULL)
435 g_free (wfilename);
436 errno = EINVAL;
437 return NULL;
440 retval = _wfreopen (wfilename, wmode, stream);
441 save_errno = errno;
443 g_free (wfilename);
444 g_free (wmode);
446 errno = save_errno;
447 return retval;
451 /* DLL loading */
452 static bool
453 init_dll_load_paths(void)
455 TCHAR path_w[MAX_PATH];
457 if (program_path && system_path && npcap_path)
458 return true;
460 /* XXX - Duplicate code in filesystem.c:configuration_init */
461 if (GetModuleFileName(NULL, path_w, MAX_PATH) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
462 return false;
465 if (!program_path) {
466 char *app_path;
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);
470 g_free(app_path);
473 if (GetSystemDirectory(path_w, MAX_PATH) == 0) {
474 return false;
477 if (!system_path) {
478 system_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
481 _tcscat_s(path_w, MAX_PATH, _T("\\Npcap"));
483 if (!npcap_path) {
484 npcap_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
487 if (program_path && system_path && npcap_path)
488 return true;
490 return false;
493 bool
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);
509 return dll_dir_set;
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
516 * separately.
519 void *
520 ws_load_library(const char *library_name)
522 char *full_path;
523 wchar_t *full_path_w;
524 HMODULE dll_h;
526 if (!init_dll_load_paths() || !library_name)
527 return NULL;
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);
535 if (dll_h) {
536 g_free(full_path);
537 g_free(full_path_w);
538 return dll_h;
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);
548 if (dll_h) {
549 g_free(full_path);
550 g_free(full_path_w);
551 return dll_h;
555 return NULL;
558 static GModule *
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);
573 g_free(wpath);
574 if (!module) {
575 return NULL;
577 GModule *mod = g_module_open(full_path, flags);
578 FreeLibrary(module);
579 return mod;
582 GModule *
583 load_wpcap_module(void)
585 char *module_name = "wpcap.dll";
586 char *full_path;
587 GModule *mod;
588 GModuleFlags flags = 0;
590 if (!init_dll_load_paths())
591 return NULL;
593 /* First try the program directory */
594 full_path = g_strconcat(program_path, G_DIR_SEPARATOR_S, module_name, NULL);
596 if (full_path) {
597 mod = g_module_open(full_path, flags);
598 g_free(full_path);
599 if (mod) {
600 return mod;
604 /* Next try the Npcap directory */
605 full_path = g_strconcat(npcap_path, G_DIR_SEPARATOR_S, module_name, NULL);
607 if (full_path) {
608 mod = load_npcap_module(full_path, flags);
609 g_free(full_path);
610 if (mod) {
611 return mod;
615 /* At last try the system directory */
616 full_path = g_strconcat(system_path, G_DIR_SEPARATOR_S, module_name, NULL);
618 if (full_path) {
619 mod = g_module_open(full_path, flags);
620 g_free(full_path);
621 if (mod) {
622 return mod;
626 return NULL;
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.
647 sa = NULL;
648 } else {
650 * We could set it up, so set up some attributes that refer
651 * to it.
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) {
675 fd_set rfds;
676 struct timeval tv = { 0, 1 };
677 int retval;
679 FD_ZERO(&rfds);
680 FD_SET(fd, &rfds);
682 retval = select(1, &rfds, NULL, NULL, &tv);
683 if (retval > -1)
684 return _close(fd);
686 return -1;
690 * Editor modelines - https://www.wireshark.org/tools/modelines.html
692 * Local Variables:
693 * c-basic-offset: 4
694 * tab-width: 8
695 * indent-tabs-mode: nil
696 * End:
698 * ex: set shiftwidth=4 tabstop=8 expandtab:
699 * :indentSize=4:tabSize=8:noTabs=true: