From Edgar Gladkich:
[obnox/wireshark/wip.git] / wsutil / file_util.c
1 /* file_util.c
2  *
3  * $Id$
4  *
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>
8  *
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.
13  *
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.
18  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  */
24
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
27  *
28  * DO NOT USE THESE FUNCTIONS DIRECTLY, USE ws_open() AND ALIKE FUNCTIONS FROM file_util.h INSTEAD!!!
29  *
30  * the following code is stripped down code copied from the GLib file glib/gstdio.h
31  * stipped down, because this is used on _WIN32 only and we use only wide char functions */
32
33 #ifndef _WIN32
34 #error "This is only for Windows"
35 #endif
36
37 #ifdef HAVE_CONFIG_H
38 #include "config.h"
39 #endif
40
41 #include <glib.h>
42
43 #include <windows.h>
44 #include <errno.h>
45 #include <wchar.h>
46 /*#include <direct.h>*/
47 #include <io.h>
48
49 #include "file_util.h"
50
51
52
53
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()
59  *
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.
66  *
67  * See the C library manual for more details about open().
68  *
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().
71  *
72  * Since: 2.6
73  */
74 int
75 ws_stdio_open (const gchar *filename,
76         int          flags,
77         int          mode)
78 {
79       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
80       int retval;
81       int save_errno;
82
83       if (wfilename == NULL)
84         {
85           errno = EINVAL;
86           return -1;
87         }
88
89       retval = _wopen (wfilename, flags, mode);
90       save_errno = errno;
91
92       g_free (wfilename);
93
94       errno = save_errno;
95       return retval;
96 }
97
98
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
103  *
104  * A wrapper for the POSIX rename() function. The rename() function
105  * renames a file, moving it between directories if required.
106  *
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.
111  *
112  * Returns: 0 if the renaming succeeded, -1 if an error occurred
113  *
114  * Since: 2.6
115  */
116 int
117 ws_stdio_rename (const gchar *oldfilename,
118           const gchar *newfilename)
119 {
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;
124
125       if (woldfilename == NULL)
126         {
127           errno = EINVAL;
128           return -1;
129         }
130
131       wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
132
133       if (wnewfilename == NULL)
134         {
135           g_free (woldfilename);
136           errno = EINVAL;
137           return -1;
138         }
139
140       if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
141         retval = 0;
142       else
143         {
144           retval = -1;
145           switch (GetLastError ())
146             {
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;
158             }
159         }
160
161       g_free (woldfilename);
162       g_free (wnewfilename);
163
164       errno = save_errno;
165       return retval;
166 }
167
168 /**
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
172  *
173  * A wrapper for the POSIX mkdir() function. The mkdir() function
174  * attempts to create a directory with the given name and permissions.
175  *
176  * See the C library manual for more details about mkdir().
177  *
178  * Returns: 0 if the directory was successfully created, -1 if an error
179  *    occurred
180  *
181  * Since: 2.6
182  */
183 int
184 ws_stdio_mkdir (const gchar *filename,
185          int          mode)
186 {
187       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
188       int retval;
189       int save_errno;
190
191       if (wfilename == NULL)
192         {
193           errno = EINVAL;
194           return -1;
195         }
196
197       retval = _wmkdir (wfilename);
198       save_errno = errno;
199
200       g_free (wfilename);
201
202       errno = save_errno;
203       return retval;
204 }
205
206 /**
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
211  *
212  * A wrapper for the POSIX stat() function. The stat() function
213  * returns information about a file.
214  *
215  * See the C library manual for more details about stat().
216  *
217  * Returns: 0 if the information was successfully retrieved, -1 if an error
218  *    occurred
219  *
220  * Since: 2.6
221  */
222 int
223 ws_stdio_stat (const gchar *filename,
224         struct stat *buf)
225 {
226       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
227       int retval;
228       int save_errno;
229       size_t len;
230
231       if (wfilename == NULL)
232         {
233           errno = EINVAL;
234           return -1;
235         }
236
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';
243
244       retval = _wstat (wfilename, (struct _stat *) buf);
245       save_errno = errno;
246
247       g_free (wfilename);
248
249       errno = save_errno;
250       return retval;
251 }
252 /**
253  * g_unlink:
254  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
255  *
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.
260  *
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.
264  *
265  * Returns: 0 if the name was successfully deleted, -1 if an error
266  *    occurred
267  *
268  * Since: 2.6
269  */
270  
271 int
272 ws_stdio_unlink (const gchar *filename)
273 {
274       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
275       int retval;
276       int save_errno;
277
278       if (wfilename == NULL)
279         {
280           errno = EINVAL;
281           return -1;
282         }
283
284       retval = _wunlink (wfilename);
285       save_errno = errno;
286
287       g_free (wfilename);
288
289       errno = save_errno;
290       return retval;
291 }
292
293 /**
294  * g_remove:
295  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
296  *
297  * A wrapper for the POSIX remove() function. The remove() function
298  * deletes a name from the filesystem.
299  *
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.
308  *
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().
313  *
314  * Returns: 0 if the file was successfully removed, -1 if an error
315  *    occurred
316  *
317  * Since: 2.6
318  */
319 int
320 ws_stdio_remove (const gchar *filename)
321 {
322       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
323       int retval;
324       int save_errno;
325
326       if (wfilename == NULL)
327         {
328           errno = EINVAL;
329           return -1;
330         }
331
332       retval = _wremove (wfilename);
333       if (retval == -1)
334         retval = _wrmdir (wfilename);
335       save_errno = errno;
336
337       g_free (wfilename);
338
339       errno = save_errno;
340       return retval;
341 }
342
343 /**
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
348  *
349  * A wrapper for the POSIX fopen() function. The fopen() function opens
350  * a file and associates a new stream with it.
351  *
352  * See the C library manual for more details about fopen().
353  *
354  * Returns: A <type>FILE</type> pointer if the file was successfully
355  *    opened, or %NULL if an error occurred
356  *
357  * Since: 2.6
358  */
359 FILE *
360 ws_stdio_fopen (const gchar *filename,
361          const gchar *mode)
362 {
363       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
364       wchar_t *wmode;
365       FILE *retval;
366       int save_errno;
367
368       if (wfilename == NULL)
369         {
370           errno = EINVAL;
371           return NULL;
372         }
373
374       wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
375
376       if (wmode == NULL)
377         {
378           g_free (wfilename);
379           errno = EINVAL;
380           return NULL;
381         }
382
383       retval = _wfopen (wfilename, wmode);
384       save_errno = errno;
385
386       g_free (wfilename);
387       g_free (wmode);
388
389       errno = save_errno;
390       return retval;
391 }
392
393 /**
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
399  *
400  * A wrapper for the POSIX freopen() function. The freopen() function
401  * opens a file and associates it with an existing stream.
402  *
403  * See the C library manual for more details about freopen().
404  *
405  * Returns: A <type>FILE</type> pointer if the file was successfully
406  *    opened, or %NULL if an error occurred.
407  *
408  * Since: 2.6
409  */
410 FILE *
411 ws_stdio_freopen (const gchar *filename,
412            const gchar *mode,
413            FILE        *stream)
414 {
415       wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
416       wchar_t *wmode;
417       FILE *retval;
418       int save_errno;
419
420       if (wfilename == NULL)
421         {
422           errno = EINVAL;
423           return NULL;
424         }
425
426       wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
427
428       if (wmode == NULL)
429         {
430           g_free (wfilename);
431           errno = EINVAL;
432           return NULL;
433         }
434
435       retval = _wfreopen (wfilename, wmode, stream);
436       save_errno = errno;
437
438       g_free (wfilename);
439       g_free (wmode);
440
441       errno = save_errno;
442       return retval;
443 }