DCERPC: factor out proto_tree_add_dcerpc_drep()
[wireshark-wip.git] / wsutil / file_util.c
blob2b90bab9ffbb09db59d25d32073c9539a61a5335
1 /* file_util.c
3 * $Id$
5 * (Originally part of the Wiretap Library, now part of the Wireshark
6 * utility library)
7 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * as published by the Free Software Foundation; either version 2
12 * of the License, or (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 /* file wrapper functions to prevent the file functions from GLib like g_open(),
26 * as code compiled with MSVC 7 and above will collide with libs linked with msvcrt.dll (MSVC 6), lib GLib is
28 * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS FROM file_util.h INSTEAD!!!
30 * the following code is stripped down code copied from the GLib file glib/gstdio.h
31 * stripped down, because this is used on _WIN32 only and we use only wide char functions */
33 #ifndef _WIN32
34 #error "This is only for Windows"
35 #endif
37 #include "config.h"
39 #include <glib.h>
41 #include <windows.h>
42 #include <errno.h>
43 #include <wchar.h>
44 #include <tchar.h>
45 /*#include <direct.h>*/
46 #include <io.h>
47 #include <stdlib.h>
49 #include "file_util.h"
51 static gchar *program_path = NULL;
52 static gchar *system_path = NULL;
54 /**
55 * g_open:
56 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
57 * @flags: as in open()
58 * @mode: as in open()
60 * A wrapper for the POSIX open() function. The open() function is
61 * used to convert a pathname into a file descriptor. Note that on
62 * POSIX systems file descriptors are implemented by the operating
63 * system. On Windows, it's the C library that implements open() and
64 * file descriptors. The actual Windows API for opening files is
65 * something different.
67 * See the C library manual for more details about open().
69 * Returns: a new file descriptor, or -1 if an error occurred. The
70 * return value can be used exactly like the return value from open().
72 * Since: 2.6
74 int
75 ws_stdio_open (const gchar *filename,
76 int flags,
77 int mode)
79 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
80 int retval;
81 int save_errno;
83 if (wfilename == NULL)
85 errno = EINVAL;
86 return -1;
89 retval = _wopen (wfilename, flags, mode);
90 save_errno = errno;
92 g_free (wfilename);
94 errno = save_errno;
95 return retval;
99 /**
100 * g_rename:
101 * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
102 * @newfilename: a pathname in the GLib file name encoding
104 * A wrapper for the POSIX rename() function. The rename() function
105 * renames a file, moving it between directories if required.
107 * See your C library manual for more details about how rename() works
108 * on your system. Note in particular that on Win9x it is not possible
109 * to rename a file if a file with the new name already exists. Also
110 * it is not possible in general on Windows to rename an open file.
112 * Returns: 0 if the renaming succeeded, -1 if an error occurred
114 * Since: 2.6
117 ws_stdio_rename (const gchar *oldfilename,
118 const gchar *newfilename)
120 wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
121 wchar_t *wnewfilename;
122 int retval;
123 int save_errno = 0;
125 if (woldfilename == NULL)
127 errno = EINVAL;
128 return -1;
131 wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
133 if (wnewfilename == NULL)
135 g_free (woldfilename);
136 errno = EINVAL;
137 return -1;
140 if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
141 retval = 0;
142 else
144 retval = -1;
145 switch (GetLastError ())
147 #define CASE(a,b) case ERROR_##a: save_errno = b; break
148 CASE (FILE_NOT_FOUND, ENOENT);
149 CASE (PATH_NOT_FOUND, ENOENT);
150 CASE (ACCESS_DENIED, EACCES);
151 CASE (NOT_SAME_DEVICE, EXDEV);
152 CASE (LOCK_VIOLATION, EACCES);
153 CASE (SHARING_VIOLATION, EACCES);
154 CASE (FILE_EXISTS, EEXIST);
155 CASE (ALREADY_EXISTS, EEXIST);
156 #undef CASE
157 default: save_errno = EIO;
161 g_free (woldfilename);
162 g_free (wnewfilename);
164 errno = save_errno;
165 return retval;
169 * g_mkdir:
170 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
171 * @mode: permissions to use for the newly created directory
173 * A wrapper for the POSIX mkdir() function. The mkdir() function
174 * attempts to create a directory with the given name and permissions.
176 * See the C library manual for more details about mkdir().
178 * Returns: 0 if the directory was successfully created, -1 if an error
179 * occurred
181 * Since: 2.6
184 ws_stdio_mkdir (const gchar *filename,
185 int mode)
187 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
188 int retval;
189 int save_errno;
191 if (wfilename == NULL)
193 errno = EINVAL;
194 return -1;
197 retval = _wmkdir (wfilename);
198 save_errno = errno;
200 g_free (wfilename);
202 errno = save_errno;
203 return retval;
207 * g_stat:
208 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
209 * @buf: a pointer to a <structname>stat</structname> struct, which
210 * will be filled with the file information
212 * A wrapper for the POSIX stat() function. The stat() function
213 * returns information about a file.
215 * See the C library manual for more details about stat().
217 * Returns: 0 if the information was successfully retrieved, -1 if an error
218 * occurred
220 * Since: 2.6
223 ws_stdio_stat64 (const gchar *filename,
224 ws_statb64 *buf)
226 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
227 int retval;
228 int save_errno;
229 size_t len;
231 if (wfilename == NULL)
233 errno = EINVAL;
234 return -1;
237 len = wcslen (wfilename);
238 while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
239 len--;
240 if (len > 0 &&
241 (!g_path_is_absolute (filename) || len > (size_t) (g_path_skip_root (filename) - filename)))
242 wfilename[len] = '\0';
244 retval = _wstati64 (wfilename, buf);
245 save_errno = errno;
247 g_free (wfilename);
249 errno = save_errno;
250 return retval;
253 * g_unlink:
254 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
256 * A wrapper for the POSIX unlink() function. The unlink() function
257 * deletes a name from the filesystem. If this was the last link to the
258 * file and no processes have it opened, the diskspace occupied by the
259 * file is freed.
261 * See your C library manual for more details about unlink(). Note
262 * that on Windows, it is in general not possible to delete files that
263 * are open to some process, or mapped into memory.
265 * Returns: 0 if the name was successfully deleted, -1 if an error
266 * occurred
268 * Since: 2.6
272 ws_stdio_unlink (const gchar *filename)
274 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
275 int retval;
276 int save_errno;
278 if (wfilename == NULL)
280 errno = EINVAL;
281 return -1;
284 retval = _wunlink (wfilename);
285 save_errno = errno;
287 g_free (wfilename);
289 errno = save_errno;
290 return retval;
294 * g_remove:
295 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
297 * A wrapper for the POSIX remove() function. The remove() function
298 * deletes a name from the filesystem.
300 * See your C library manual for more details about how remove() works
301 * on your system. On Unix, remove() removes also directories, as it
302 * calls unlink() for files and rmdir() for directories. On Windows,
303 * although remove() in the C library only works for files, this
304 * function tries first remove() and then if that fails rmdir(), and
305 * thus works for both files and directories. Note however, that on
306 * Windows, it is in general not possible to remove a file that is
307 * open to some process, or mapped into memory.
309 * If this function fails on Windows you can't infer too much from the
310 * errno value. rmdir() is tried regardless of what caused remove() to
311 * fail. Any errno value set by remove() will be overwritten by that
312 * set by rmdir().
314 * Returns: 0 if the file was successfully removed, -1 if an error
315 * occurred
317 * Since: 2.6
320 ws_stdio_remove (const gchar *filename)
322 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
323 int retval;
324 int save_errno;
326 if (wfilename == NULL)
328 errno = EINVAL;
329 return -1;
332 retval = _wremove (wfilename);
333 if (retval == -1)
334 retval = _wrmdir (wfilename);
335 save_errno = errno;
337 g_free (wfilename);
339 errno = save_errno;
340 return retval;
344 * g_fopen:
345 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
346 * @mode: a string describing the mode in which the file should be
347 * opened
349 * A wrapper for the POSIX fopen() function. The fopen() function opens
350 * a file and associates a new stream with it.
352 * See the C library manual for more details about fopen().
354 * Returns: A <type>FILE</type> pointer if the file was successfully
355 * opened, or %NULL if an error occurred
357 * Since: 2.6
359 FILE *
360 ws_stdio_fopen (const gchar *filename,
361 const gchar *mode)
363 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
364 wchar_t *wmode;
365 FILE *retval;
366 int save_errno;
368 if (wfilename == NULL)
370 errno = EINVAL;
371 return NULL;
374 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
376 if (wmode == NULL)
378 g_free (wfilename);
379 errno = EINVAL;
380 return NULL;
383 retval = _wfopen (wfilename, wmode);
384 save_errno = errno;
386 g_free (wfilename);
387 g_free (wmode);
389 errno = save_errno;
390 return retval;
394 * g_freopen:
395 * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
396 * @mode: a string describing the mode in which the file should be
397 * opened
398 * @stream: an existing stream which will be reused, or %NULL
400 * A wrapper for the POSIX freopen() function. The freopen() function
401 * opens a file and associates it with an existing stream.
403 * See the C library manual for more details about freopen().
405 * Returns: A <type>FILE</type> pointer if the file was successfully
406 * opened, or %NULL if an error occurred.
408 * Since: 2.6
410 FILE *
411 ws_stdio_freopen (const gchar *filename,
412 const gchar *mode,
413 FILE *stream)
415 wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
416 wchar_t *wmode;
417 FILE *retval;
418 int save_errno;
420 if (wfilename == NULL)
422 errno = EINVAL;
423 return NULL;
426 wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
428 if (wmode == NULL)
430 g_free (wfilename);
431 errno = EINVAL;
432 return NULL;
435 retval = _wfreopen (wfilename, wmode, stream);
436 save_errno = errno;
438 g_free (wfilename);
439 g_free (wmode);
441 errno = save_errno;
442 return retval;
446 /* DLL loading */
447 static gboolean
448 init_dll_load_paths()
450 TCHAR path_w[MAX_PATH];
452 if (program_path && system_path)
453 return TRUE;
455 /* XXX - Duplicate code in filesystem.c:init_progfile_dir */
456 if (GetModuleFileName(NULL, path_w, MAX_PATH) == 0 || GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
457 return FALSE;
460 if (!program_path) {
461 gchar *app_path;
462 app_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
463 /* We could use PathRemoveFileSpec here but we'd have to link to Shlwapi.dll */
464 program_path = g_path_get_dirname(app_path);
465 g_free(app_path);
468 if (GetSystemDirectory(path_w, MAX_PATH) == 0) {
469 return FALSE;
472 if (!system_path) {
473 system_path = g_utf16_to_utf8(path_w, -1, NULL, NULL, NULL);
476 if (program_path && system_path)
477 return TRUE;
479 return FALSE;
482 gboolean
483 ws_init_dll_search_path()
485 gboolean dll_dir_set = FALSE;
486 wchar_t *program_path_w;
488 typedef BOOL (WINAPI *SetDllDirectoryHandler)(LPCTSTR);
489 SetDllDirectoryHandler PSetDllDirectory;
491 PSetDllDirectory = (SetDllDirectoryHandler) GetProcAddress(GetModuleHandle(_T("kernel32.dll")), "SetDllDirectoryW");
492 if (PSetDllDirectory) {
493 dll_dir_set = PSetDllDirectory(_T(""));
496 if (!dll_dir_set && init_dll_load_paths()) {
497 program_path_w = g_utf8_to_utf16(program_path, -1, NULL, NULL, NULL);
498 SetCurrentDirectory(program_path_w);
499 g_free(program_path_w);
502 return dll_dir_set;
506 * Internally g_module_open uses LoadLibrary on Windows and returns an
507 * HMODULE cast to a GModule *. However there's no guarantee that this
508 * will always be the case, so we call LoadLibrary and g_module_open
509 * separately.
512 void *
513 ws_load_library(gchar *library_name)
515 gchar *full_path;
516 wchar_t *full_path_w;
517 HMODULE dll_h;
519 if (!init_dll_load_paths() || !library_name)
520 return NULL;
522 /* First try the program directory */
523 full_path = g_module_build_path(program_path, library_name);
524 full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
526 if (full_path && full_path_w) {
527 dll_h = LoadLibraryW(full_path_w);
528 if (dll_h) {
529 g_free(full_path);
530 g_free(full_path_w);
531 return dll_h;
535 /* Next try the system directory */
536 full_path = g_module_build_path(system_path, library_name);
537 full_path_w = g_utf8_to_utf16(full_path, -1, NULL, NULL, NULL);
539 if (full_path && full_path_w) {
540 dll_h = LoadLibraryW(full_path_w);
541 if (dll_h) {
542 g_free(full_path);
543 g_free(full_path_w);
544 return dll_h;
548 return NULL;
551 GModule *
552 ws_module_open(gchar *module_name, GModuleFlags flags)
554 gchar *full_path;
555 GModule *mod;
557 if (!init_dll_load_paths() || !module_name)
558 return NULL;
560 /* First try the program directory */
561 full_path = g_module_build_path(program_path, module_name);
563 if (full_path) {
564 mod = g_module_open(full_path, flags);
565 if (mod) {
566 g_free(full_path);
567 return mod;
571 /* Next try the system directory */
572 full_path = g_module_build_path(system_path, module_name);
574 if (full_path) {
575 mod = g_module_open(full_path, flags);
576 if (mod) {
577 g_free(full_path);
578 return mod;
582 return NULL;
585 /* utf8 version of getenv, needed to get win32 filename paths */
586 char *
587 getenv_utf8(const char *varname)
589 char *envvar;
590 wchar_t *envvarw;
591 wchar_t *varnamew;
593 envvar = getenv(varname);
595 /* since GLib 2.6 we need an utf8 version of the filename */
596 /* using the wide char version of getenv should work under all circumstances */
598 /* convert given varname to utf16, needed by _wgetenv */
599 varnamew = g_utf8_to_utf16(varname, -1, NULL, NULL, NULL);
600 if (varnamew == NULL) {
601 return envvar;
604 /* use wide char version of getenv */
605 envvarw = _wgetenv(varnamew);
606 g_free(varnamew);
607 if (envvarw == NULL) {
608 return envvar;
611 /* convert value to utf8 */
612 envvar = g_utf16_to_utf8(envvarw, -1, NULL, NULL, NULL);
613 /* XXX - memleak */
615 return envvar;
618 /** Create or open a "Wireshark is running" mutex.
620 #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B"
622 static SECURITY_ATTRIBUTES *sec_attributes_;
624 void create_app_running_mutex() {
625 SECURITY_ATTRIBUTES *sa = NULL;
627 if (!sec_attributes_) sec_attributes_ = g_new0(SECURITY_ATTRIBUTES, 1);
629 sec_attributes_->nLength = sizeof(SECURITY_ATTRIBUTES);
630 sec_attributes_->lpSecurityDescriptor = g_new0(SECURITY_DESCRIPTOR, 1);
631 sec_attributes_->bInheritHandle = TRUE;
632 if (InitializeSecurityDescriptor(sec_attributes_->lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION)) {
633 if (SetSecurityDescriptorDacl(sec_attributes_->lpSecurityDescriptor, TRUE, NULL, FALSE)) {
634 sa = sec_attributes_;
638 if (!sa) {
639 g_free(sec_attributes_->lpSecurityDescriptor);
640 g_free(sec_attributes_);
641 sec_attributes_ = NULL;
643 CreateMutex(sa, FALSE, _T("Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));
644 CreateMutex(sa, FALSE, _T("Global\\Wireshark-is-running-{") _T(WIRESHARK_IS_RUNNING_UUID) _T("}"));