1 /* gstdio.c - wrappers for C library functions
2  *
3  * Copyright 2004 Tor Lillqvist
4  *
5  * GLib is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * GLib is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with GLib; see the file COPYING.LIB.  If not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20 
21 #include "config.h"
22 #include "glibconfig.h"
23 
24 #define G_STDIO_NO_WRAP_ON_UNIX
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 
30 #ifdef HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 
34 #ifdef G_OS_WIN32
35 #include <windows.h>
36 #include <errno.h>
37 #include <wchar.h>
38 #include <direct.h>
39 #include <io.h>
40 #include <sys/utime.h>
41 #else
42 #include <utime.h>
43 #endif
44 
45 #include "gstdio.h"
46 
47 
48 #if !defined (G_OS_UNIX) && !defined (G_OS_WIN32) && !defined (G_OS_BEOS)
49 #error Please port this to your operating system
50 #endif
51 
52 #if defined (_MSC_VER) && !defined(_WIN64)
53 #undef _wstat
54 #define _wstat _wstat32
55 #endif
56 
57 /**
58  * g_access:
59  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
60  * @mode: as in access()
61  *
62  * A wrapper for the POSIX access() function. This function is used to
63  * test a pathname for one or several of read, write or execute
64  * permissions, or just existence.
65  *
66  * On Windows, the file protection mechanism is not at all POSIX-like,
67  * and the underlying function in the C library only checks the
68  * FAT-style READONLY attribute, and does not look at the ACL of a
69  * file at all. This function is this in practise almost useless on
70  * Windows. Software that needs to handle file permissions on Windows
71  * more exactly should use the Win32 API.
72  *
73  * See your C library manual for more details about access().
74  *
75  * Returns: zero if the pathname refers to an existing file system
76  * object that has all the tested permissions, or -1 otherwise or on
77  * error.
78  *
79  * Since: 2.8
80  */
81 int
g_access(const gchar * filename,int mode)82 g_access (const gchar *filename,
83 	  int          mode)
84 {
85 #ifdef G_OS_WIN32
86   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
87   int retval;
88   int save_errno;
89 
90   if (wfilename == NULL)
91     {
92       errno = EINVAL;
93       return -1;
94     }
95 
96 #ifndef X_OK
97 #define X_OK 1
98 #endif
99 
100   retval = _waccess (wfilename, mode & ~X_OK);
101   save_errno = errno;
102 
103   g_free (wfilename);
104 
105   errno = save_errno;
106   return retval;
107 #else
108   return access (filename, mode);
109 #endif
110 }
111 
112 /**
113  * g_chmod:
114  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
115  * @mode: as in chmod()
116  *
117  * A wrapper for the POSIX chmod() function. The chmod() function is
118  * used to set the permissions of a file system object.
119  *
120  * On Windows the file protection mechanism is not at all POSIX-like,
121  * and the underlying chmod() function in the C library just sets or
122  * clears the FAT-style READONLY attribute. It does not touch any
123  * ACL. Software that needs to manage file permissions on Windows
124  * exactly should use the Win32 API.
125  *
126  * See your C library manual for more details about chmod().
127  *
128  * Returns: zero if the operation succeeded, -1 on error.
129  *
130  * Since: 2.8
131  */
132 int
g_chmod(const gchar * filename,int mode)133 g_chmod (const gchar *filename,
134 	 int          mode)
135 {
136 #ifdef G_OS_WIN32
137   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
138   int retval;
139   int save_errno;
140 
141   if (wfilename == NULL)
142     {
143       errno = EINVAL;
144       return -1;
145     }
146 
147   retval = _wchmod (wfilename, mode);
148   save_errno = errno;
149 
150   g_free (wfilename);
151 
152   errno = save_errno;
153   return retval;
154 #else
155   return chmod (filename, mode);
156 #endif
157 }
158 /**
159  * g_open:
160  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
161  * @flags: as in open()
162  * @mode: as in open()
163  *
164  * A wrapper for the POSIX open() function. The open() function is
165  * used to convert a pathname into a file descriptor.
166  *
167  * On POSIX systems file descriptors are implemented by the operating
168  * system. On Windows, it's the C library that implements open() and
169  * file descriptors. The actual Win32 API for opening files is quite
170  * different, see MSDN documentation for CreateFile(). The Win32 API
171  * uses file handles, which are more randomish integers, not small
172  * integers like file descriptors.
173  *
174  * Because file descriptors are specific to the C library on Windows,
175  * the file descriptor returned by this function makes sense only to
176  * functions in the same C library. Thus if the GLib-using code uses a
177  * different C library than GLib does, the file descriptor returned by
178  * this function cannot be passed to C library functions like write()
179  * or read().
180  *
181  * See your C library manual for more details about open().
182  *
183  * Returns: a new file descriptor, or -1 if an error occurred. The
184  * return value can be used exactly like the return value from open().
185  *
186  * Since: 2.6
187  */
188 int
g_open(const gchar * filename,int flags,int mode)189 g_open (const gchar *filename,
190 	int          flags,
191 	int          mode)
192 {
193 #ifdef G_OS_WIN32
194   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
195   int retval;
196   int save_errno;
197 
198   if (wfilename == NULL)
199     {
200       errno = EINVAL;
201       return -1;
202     }
203 
204   retval = _wopen (wfilename, flags, mode);
205   save_errno = errno;
206 
207   g_free (wfilename);
208 
209   errno = save_errno;
210   return retval;
211 #else
212   return open (filename, flags, mode);
213 #endif
214 }
215 
216 /**
217  * g_creat:
218  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
219  * @mode: as in creat()
220  *
221  * A wrapper for the POSIX creat() function. The creat() function is
222  * used to convert a pathname into a file descriptor, creating a file
223  * if necessary.
224 
225  * On POSIX systems file descriptors are implemented by the operating
226  * system. On Windows, it's the C library that implements creat() and
227  * file descriptors. The actual Windows API for opening files is
228  * different, see MSDN documentation for CreateFile(). The Win32 API
229  * uses file handles, which are more randomish integers, not small
230  * integers like file descriptors.
231  *
232  * Because file descriptors are specific to the C library on Windows,
233  * the file descriptor returned by this function makes sense only to
234  * functions in the same C library. Thus if the GLib-using code uses a
235  * different C library than GLib does, the file descriptor returned by
236  * this function cannot be passed to C library functions like write()
237  * or read().
238  *
239  * See your C library manual for more details about creat().
240  *
241  * Returns: a new file descriptor, or -1 if an error occurred. The
242  * return value can be used exactly like the return value from creat().
243  *
244  * Since: 2.8
245  */
246 int
g_creat(const gchar * filename,int mode)247 g_creat (const gchar *filename,
248 	 int          mode)
249 {
250 #ifdef G_OS_WIN32
251   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
252   int retval;
253   int save_errno;
254 
255   if (wfilename == NULL)
256     {
257       errno = EINVAL;
258       return -1;
259     }
260 
261   retval = _wcreat (wfilename, mode);
262   save_errno = errno;
263 
264   g_free (wfilename);
265 
266   errno = save_errno;
267   return retval;
268 #else
269   return creat (filename, mode);
270 #endif
271 }
272 
273 /**
274  * g_rename:
275  * @oldfilename: a pathname in the GLib file name encoding (UTF-8 on Windows)
276  * @newfilename: a pathname in the GLib file name encoding
277  *
278  * A wrapper for the POSIX rename() function. The rename() function
279  * renames a file, moving it between directories if required.
280  *
281  * See your C library manual for more details about how rename() works
282  * on your system. It is not possible in general on Windows to rename
283  * a file that is open to some process.
284  *
285  * Returns: 0 if the renaming succeeded, -1 if an error occurred
286  *
287  * Since: 2.6
288  */
289 int
g_rename(const gchar * oldfilename,const gchar * newfilename)290 g_rename (const gchar *oldfilename,
291 	  const gchar *newfilename)
292 {
293 #ifdef G_OS_WIN32
294   wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
295   wchar_t *wnewfilename;
296   int retval;
297   int save_errno = 0;
298 
299   if (woldfilename == NULL)
300     {
301       errno = EINVAL;
302       return -1;
303     }
304 
305   wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
306 
307   if (wnewfilename == NULL)
308     {
309       g_free (woldfilename);
310       errno = EINVAL;
311       return -1;
312     }
313 
314   if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
315     retval = 0;
316   else
317     {
318       retval = -1;
319       switch (GetLastError ())
320 	{
321 #define CASE(a,b) case ERROR_##a: save_errno = b; break
322 	  CASE (FILE_NOT_FOUND, ENOENT);
323 	  CASE (PATH_NOT_FOUND, ENOENT);
324 	  CASE (ACCESS_DENIED, EACCES);
325 	  CASE (NOT_SAME_DEVICE, EXDEV);
326 	  CASE (LOCK_VIOLATION, EACCES);
327 	  CASE (SHARING_VIOLATION, EACCES);
328 	  CASE (FILE_EXISTS, EEXIST);
329 	  CASE (ALREADY_EXISTS, EEXIST);
330 #undef CASE
331 	default: save_errno = EIO;
332 	}
333     }
334 
335   g_free (woldfilename);
336   g_free (wnewfilename);
337 
338   errno = save_errno;
339   return retval;
340 #else
341   return rename (oldfilename, newfilename);
342 #endif
343 }
344 
345 /**
346  * g_mkdir:
347  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
348  * @mode: permissions to use for the newly created directory
349  *
350  * A wrapper for the POSIX mkdir() function. The mkdir() function
351  * attempts to create a directory with the given name and permissions.
352  * The mode argument is ignored on Windows.
353  *
354  * See your C library manual for more details about mkdir().
355  *
356  * Returns: 0 if the directory was successfully created, -1 if an error
357  *    occurred
358  *
359  * Since: 2.6
360  */
361 int
g_mkdir(const gchar * filename,int mode)362 g_mkdir (const gchar *filename,
363 	 int          mode)
364 {
365 #ifdef G_OS_WIN32
366   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
367   int retval;
368   int save_errno;
369 
370   if (wfilename == NULL)
371     {
372       errno = EINVAL;
373       return -1;
374     }
375 
376   retval = _wmkdir (wfilename);
377   save_errno = errno;
378 
379   g_free (wfilename);
380 
381   errno = save_errno;
382   return retval;
383 #else
384   return mkdir (filename, mode);
385 #endif
386 }
387 
388 /**
389  * g_chdir:
390  * @path: a pathname in the GLib file name encoding (UTF-8 on Windows)
391  *
392  * A wrapper for the POSIX chdir() function. The function changes the
393  * current directory of the process to @path.
394  *
395  * See your C library manual for more details about chdir().
396  *
397  * Returns: 0 on success, -1 if an error occurred.
398  *
399  * Since: 2.8
400  */
401 int
g_chdir(const gchar * path)402 g_chdir (const gchar *path)
403 {
404 #ifdef G_OS_WIN32
405   wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
406   int retval;
407   int save_errno;
408 
409   if (wpath == NULL)
410     {
411       errno = EINVAL;
412       return -1;
413     }
414 
415   retval = _wchdir (wpath);
416   save_errno = errno;
417 
418   g_free (wpath);
419 
420   errno = save_errno;
421   return retval;
422 #else
423   return chdir (path);
424 #endif
425 }
426 
427 /**
428  * GStatBuf:
429  *
430  * A type corresponding to the appropriate struct type for the stat
431  * system call, depending on the platform and/or compiler being used.
432  *
433  * See g_stat() for more information.
434  **/
435 /**
436  * g_stat:
437  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
438  * @buf: a pointer to a <structname>stat</structname> struct, which
439  *    will be filled with the file information
440  *
441  * A wrapper for the POSIX stat() function. The stat() function
442  * returns information about a file. On Windows the stat() function in
443  * the C library checks only the FAT-style READONLY attribute and does
444  * not look at the ACL at all. Thus on Windows the protection bits in
445  * the st_mode field are a fabrication of little use.
446  *
447  * On Windows the Microsoft C libraries have several variants of the
448  * <structname>stat</structname> struct and stat() function with names
449  * like "_stat", "_stat32", "_stat32i64" and "_stat64i32". The one
450  * used here is for 32-bit code the one with 32-bit size and time
451  * fields, specifically called "_stat32".
452  *
453  * In Microsoft's compiler, by default "struct stat" means one with
454  * 64-bit time fields while in MinGW "struct stat" is the legacy one
455  * with 32-bit fields. To hopefully clear up this messs, the gstdio.h
456  * header defines a type GStatBuf which is the appropriate struct type
457  * depending on the platform and/or compiler being used. On POSIX it
458  * is just "struct stat", but note that even on POSIX platforms,
459  * "stat" might be a macro.
460  *
461  * See your C library manual for more details about stat().
462  *
463  * Returns: 0 if the information was successfully retrieved, -1 if an error
464  *    occurred
465  *
466  * Since: 2.6
467  */
468 int
g_stat(const gchar * filename,GStatBuf * buf)469 g_stat (const gchar *filename,
470 	GStatBuf    *buf)
471 {
472 #ifdef G_OS_WIN32
473   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
474   int retval;
475   int save_errno;
476   int len;
477 
478   if (wfilename == NULL)
479     {
480       errno = EINVAL;
481       return -1;
482     }
483 
484   len = wcslen (wfilename);
485   while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
486     len--;
487   if (len > 0 &&
488       (!g_path_is_absolute (filename) || len > g_path_skip_root (filename) - filename))
489     wfilename[len] = '\0';
490 
491   retval = _wstat (wfilename, buf);
492   save_errno = errno;
493 
494   g_free (wfilename);
495 
496   errno = save_errno;
497   return retval;
498 #else
499   return stat (filename, buf);
500 #endif
501 }
502 
503 /**
504  * g_lstat:
505  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
506  * @buf: a pointer to a <structname>stat</structname> struct, which
507  *    will be filled with the file information
508  *
509  * A wrapper for the POSIX lstat() function. The lstat() function is
510  * like stat() except that in the case of symbolic links, it returns
511  * information about the symbolic link itself and not the file that it
512  * refers to. If the system does not support symbolic links g_lstat()
513  * is identical to g_stat().
514  *
515  * See your C library manual for more details about lstat().
516  *
517  * Returns: 0 if the information was successfully retrieved, -1 if an error
518  *    occurred
519  *
520  * Since: 2.6
521  */
522 int
g_lstat(const gchar * filename,GStatBuf * buf)523 g_lstat (const gchar *filename,
524 	 GStatBuf    *buf)
525 {
526 #ifdef HAVE_LSTAT
527   /* This can't be Win32, so don't do the widechar dance. */
528   return lstat (filename, buf);
529 #else
530   return g_stat (filename, buf);
531 #endif
532 }
533 
534 /**
535  * g_unlink:
536  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
537  *
538  * A wrapper for the POSIX unlink() function. The unlink() function
539  * deletes a name from the filesystem. If this was the last link to the
540  * file and no processes have it opened, the diskspace occupied by the
541  * file is freed.
542  *
543  * See your C library manual for more details about unlink(). Note
544  * that on Windows, it is in general not possible to delete files that
545  * are open to some process, or mapped into memory.
546  *
547  * Returns: 0 if the name was successfully deleted, -1 if an error
548  *    occurred
549  *
550  * Since: 2.6
551  */
552 int
g_unlink(const gchar * filename)553 g_unlink (const gchar *filename)
554 {
555 #ifdef G_OS_WIN32
556   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
557   int retval;
558   int save_errno;
559 
560   if (wfilename == NULL)
561     {
562       errno = EINVAL;
563       return -1;
564     }
565 
566   retval = _wunlink (wfilename);
567   save_errno = errno;
568 
569   g_free (wfilename);
570 
571   errno = save_errno;
572   return retval;
573 #else
574   return unlink (filename);
575 #endif
576 }
577 
578 /**
579  * g_remove:
580  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
581  *
582  * A wrapper for the POSIX remove() function. The remove() function
583  * deletes a name from the filesystem.
584  *
585  * See your C library manual for more details about how remove() works
586  * on your system. On Unix, remove() removes also directories, as it
587  * calls unlink() for files and rmdir() for directories. On Windows,
588  * although remove() in the C library only works for files, this
589  * function tries first remove() and then if that fails rmdir(), and
590  * thus works for both files and directories. Note however, that on
591  * Windows, it is in general not possible to remove a file that is
592  * open to some process, or mapped into memory.
593  *
594  * If this function fails on Windows you can't infer too much from the
595  * errno value. rmdir() is tried regardless of what caused remove() to
596  * fail. Any errno value set by remove() will be overwritten by that
597  * set by rmdir().
598  *
599  * Returns: 0 if the file was successfully removed, -1 if an error
600  *    occurred
601  *
602  * Since: 2.6
603  */
604 int
g_remove(const gchar * filename)605 g_remove (const gchar *filename)
606 {
607 #ifdef G_OS_WIN32
608   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
609   int retval;
610   int save_errno;
611 
612   if (wfilename == NULL)
613     {
614       errno = EINVAL;
615       return -1;
616     }
617 
618   retval = _wremove (wfilename);
619   if (retval == -1)
620     retval = _wrmdir (wfilename);
621   save_errno = errno;
622 
623   g_free (wfilename);
624 
625   errno = save_errno;
626   return retval;
627 #else
628   return remove (filename);
629 #endif
630 }
631 
632 /**
633  * g_rmdir:
634  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
635  *
636  * A wrapper for the POSIX rmdir() function. The rmdir() function
637  * deletes a directory from the filesystem.
638  *
639  * See your C library manual for more details about how rmdir() works
640  * on your system.
641  *
642  * Returns: 0 if the directory was successfully removed, -1 if an error
643  *    occurred
644  *
645  * Since: 2.6
646  */
647 int
g_rmdir(const gchar * filename)648 g_rmdir (const gchar *filename)
649 {
650 #ifdef G_OS_WIN32
651   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
652   int retval;
653   int save_errno;
654 
655   if (wfilename == NULL)
656     {
657       errno = EINVAL;
658       return -1;
659     }
660 
661   retval = _wrmdir (wfilename);
662   save_errno = errno;
663 
664   g_free (wfilename);
665 
666   errno = save_errno;
667   return retval;
668 #else
669   return rmdir (filename);
670 #endif
671 }
672 
673 /**
674  * g_fopen:
675  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
676  * @mode: a string describing the mode in which the file should be
677  *   opened
678  *
679  * A wrapper for the stdio fopen() function. The fopen() function
680  * opens a file and associates a new stream with it.
681  *
682  * Because file descriptors are specific to the C library on Windows,
683  * and a file descriptor is partof the <type>FILE</type> struct, the
684  * <type>FILE</type> pointer returned by this function makes sense
685  * only to functions in the same C library. Thus if the GLib-using
686  * code uses a different C library than GLib does, the
687  * <type>FILE</type> pointer returned by this function cannot be
688  * passed to C library functions like fprintf() or fread().
689  *
690  * See your C library manual for more details about fopen().
691  *
692  * Returns: A <type>FILE</type> pointer if the file was successfully
693  *    opened, or %NULL if an error occurred
694  *
695  * Since: 2.6
696  */
697 FILE *
g_fopen(const gchar * filename,const gchar * mode)698 g_fopen (const gchar *filename,
699 	 const gchar *mode)
700 {
701 #ifdef G_OS_WIN32
702   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
703   wchar_t *wmode;
704   FILE *retval;
705   int save_errno;
706 
707   if (wfilename == NULL)
708     {
709       errno = EINVAL;
710       return NULL;
711     }
712 
713   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
714 
715   if (wmode == NULL)
716     {
717       g_free (wfilename);
718       errno = EINVAL;
719       return NULL;
720     }
721 
722   retval = _wfopen (wfilename, wmode);
723   save_errno = errno;
724 
725   g_free (wfilename);
726   g_free (wmode);
727 
728   errno = save_errno;
729   return retval;
730 #else
731   return fopen (filename, mode);
732 #endif
733 }
734 
735 /**
736  * g_freopen:
737  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
738  * @mode: a string describing the mode in which the file should be
739  *   opened
740  * @stream: an existing stream which will be reused, or %NULL
741  *
742  * A wrapper for the POSIX freopen() function. The freopen() function
743  * opens a file and associates it with an existing stream.
744  *
745  * See your C library manual for more details about freopen().
746  *
747  * Returns: A <type>FILE</type> pointer if the file was successfully
748  *    opened, or %NULL if an error occurred.
749  *
750  * Since: 2.6
751  */
752 FILE *
g_freopen(const gchar * filename,const gchar * mode,FILE * stream)753 g_freopen (const gchar *filename,
754 	   const gchar *mode,
755 	   FILE        *stream)
756 {
757 #ifdef G_OS_WIN32
758   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
759   wchar_t *wmode;
760   FILE *retval;
761   int save_errno;
762 
763   if (wfilename == NULL)
764     {
765       errno = EINVAL;
766       return NULL;
767     }
768 
769   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
770 
771   if (wmode == NULL)
772     {
773       g_free (wfilename);
774       errno = EINVAL;
775       return NULL;
776     }
777 
778   retval = _wfreopen (wfilename, wmode, stream);
779   save_errno = errno;
780 
781   g_free (wfilename);
782   g_free (wmode);
783 
784   errno = save_errno;
785   return retval;
786 #else
787   return freopen (filename, mode, stream);
788 #endif
789 }
790 
791 /**
792  * g_utime:
793  * @filename: a pathname in the GLib file name encoding (UTF-8 on Windows)
794  * @utb: a pointer to a struct utimbuf.
795  *
796  * A wrapper for the POSIX utime() function. The utime() function
797  * sets the access and modification timestamps of a file.
798  *
799  * See your C library manual for more details about how utime() works
800  * on your system.
801  *
802  * Returns: 0 if the operation was successful, -1 if an error
803  *    occurred
804  *
805  * Since: 2.18
806  */
807 int
g_utime(const gchar * filename,struct utimbuf * utb)808 g_utime (const gchar    *filename,
809 	 struct utimbuf *utb)
810 {
811 #ifdef G_OS_WIN32
812   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
813   int retval;
814   int save_errno;
815 
816   if (wfilename == NULL)
817     {
818       errno = EINVAL;
819       return -1;
820     }
821 
822   retval = _wutime (wfilename, (struct _utimbuf*) utb);
823   save_errno = errno;
824 
825   g_free (wfilename);
826 
827   errno = save_errno;
828   return retval;
829 #else
830   return utime (filename, utb);
831 #endif
832 }
833