• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* gstdio.c - wrappers for C library functions
2  *
3  * Copyright 2004 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library 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 License
16  * along with this library; if not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "config.h"
20 #include "glibconfig.h"
21 
22 /* Don’t redefine (for example) g_open() to open(), since we actually want to
23  * define g_open() in this file and export it as a symbol. See gstdio.h. */
24 #define G_STDIO_WRAP_ON_UNIX
25 
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 
30 #ifdef G_OS_UNIX
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 #include <stdlib.h> /* for MB_CUR_MAX */
42 #else
43 #include <utime.h>
44 #include <errno.h>
45 #endif
46 
47 #include "gstdio.h"
48 #include "gstdioprivate.h"
49 
50 #if !defined (G_OS_UNIX) && !defined (G_OS_WIN32)
51 #error Please port this to your operating system
52 #endif
53 
54 #if defined (_MSC_VER) && !defined(_WIN64)
55 #undef _wstat
56 #define _wstat _wstat32
57 #endif
58 
59 #if defined (G_OS_WIN32)
60 
61 /* We can't include Windows DDK and Windows SDK simultaneously,
62  * so let's copy this here from MinGW-w64 DDK.
63  * The structure is ultimately documented here:
64  * https://msdn.microsoft.com/en-us/library/ff552012(v=vs.85).aspx
65  */
66 typedef struct _REPARSE_DATA_BUFFER
67 {
68   ULONG  ReparseTag;
69   USHORT ReparseDataLength;
70   USHORT Reserved;
71   union
72   {
73     struct
74     {
75       USHORT SubstituteNameOffset;
76       USHORT SubstituteNameLength;
77       USHORT PrintNameOffset;
78       USHORT PrintNameLength;
79       ULONG  Flags;
80       WCHAR  PathBuffer[1];
81     } SymbolicLinkReparseBuffer;
82     struct
83     {
84       USHORT SubstituteNameOffset;
85       USHORT SubstituteNameLength;
86       USHORT PrintNameOffset;
87       USHORT PrintNameLength;
88       WCHAR  PathBuffer[1];
89     } MountPointReparseBuffer;
90     struct
91     {
92       UCHAR  DataBuffer[1];
93     } GenericReparseBuffer;
94   };
95 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
96 
97 static int
w32_error_to_errno(DWORD error_code)98 w32_error_to_errno (DWORD error_code)
99 {
100   switch (error_code)
101     {
102     case ERROR_ACCESS_DENIED:
103       return EACCES;
104       break;
105     case ERROR_ALREADY_EXISTS:
106     case ERROR_FILE_EXISTS:
107       return EEXIST;
108     case ERROR_FILE_NOT_FOUND:
109       return ENOENT;
110       break;
111     case ERROR_INVALID_FUNCTION:
112       return EFAULT;
113       break;
114     case ERROR_INVALID_HANDLE:
115       return EBADF;
116       break;
117     case ERROR_INVALID_PARAMETER:
118       return EINVAL;
119       break;
120     case ERROR_LOCK_VIOLATION:
121     case ERROR_SHARING_VIOLATION:
122       return EACCES;
123       break;
124     case ERROR_NOT_ENOUGH_MEMORY:
125     case ERROR_OUTOFMEMORY:
126       return ENOMEM;
127       break;
128     case ERROR_NOT_SAME_DEVICE:
129       return EXDEV;
130       break;
131     case ERROR_PATH_NOT_FOUND:
132       return ENOENT; /* or ELOOP, or ENAMETOOLONG */
133       break;
134     default:
135       return EIO;
136       break;
137     }
138 }
139 
140 #include "gstdio-private.c"
141 
142 /* Windows implementation of fopen() does not accept modes such as
143  * "wb+". The 'b' needs to be appended to "w+", i.e. "w+b". Note
144  * that otherwise these 2 modes are supposed to be aliases, hence
145  * swappable at will. TODO: Is this still true?
146  */
147 static void
_g_win32_fix_mode(wchar_t * mode)148 _g_win32_fix_mode (wchar_t *mode)
149 {
150   wchar_t *ptr;
151   wchar_t temp;
152 
153   ptr = wcschr (mode, L'+');
154   if (ptr != NULL && (ptr - mode) > 1)
155     {
156       temp = mode[1];
157       mode[1] = *ptr;
158       *ptr = temp;
159     }
160 }
161 
162 /* From
163  * https://support.microsoft.com/en-ca/help/167296/how-to-convert-a-unix-time-t-to-a-win32-filetime-or-systemtime
164  * FT = UT * 10000000 + 116444736000000000.
165  * Therefore:
166  * UT = (FT - 116444736000000000) / 10000000.
167  * Converts FILETIME to unix epoch time in form
168  * of a signed 64-bit integer (can be negative).
169  *
170  * The function that does the reverse can be found in
171  * gio/glocalfileinfo.c.
172  */
173 static gint64
_g_win32_filetime_to_unix_time(const FILETIME * ft,gint32 * nsec)174 _g_win32_filetime_to_unix_time (const FILETIME *ft,
175                                 gint32         *nsec)
176 {
177   gint64 result;
178   /* 1 unit of FILETIME is 100ns */
179   const gint64 hundreds_of_usec_per_sec = 10000000;
180   /* The difference between January 1, 1601 UTC (FILETIME epoch) and UNIX epoch
181    * in hundreds of nanoseconds.
182    */
183   const gint64 filetime_unix_epoch_offset = 116444736000000000;
184 
185   result = ((gint64) ft->dwLowDateTime) | (((gint64) ft->dwHighDateTime) << 32);
186   result -= filetime_unix_epoch_offset;
187 
188   if (nsec)
189     *nsec = (result % hundreds_of_usec_per_sec) * 100;
190 
191   return result / hundreds_of_usec_per_sec;
192 }
193 
194 #  ifdef _MSC_VER
195 #    ifndef S_IXUSR
196 #      define _S_IRUSR _S_IREAD
197 #      define _S_IWUSR _S_IWRITE
198 #      define _S_IXUSR _S_IEXEC
199 #      define S_IRUSR _S_IRUSR
200 #      define S_IWUSR _S_IWUSR
201 #      define S_IXUSR _S_IXUSR
202 #      define S_IRGRP (S_IRUSR >> 3)
203 #      define S_IWGRP (S_IWUSR >> 3)
204 #      define S_IXGRP (S_IXUSR >> 3)
205 #      define S_IROTH (S_IRGRP >> 3)
206 #      define S_IWOTH (S_IWGRP >> 3)
207 #      define S_IXOTH (S_IXGRP >> 3)
208 #    endif
209 #    ifndef S_ISDIR
210 #      define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
211 #    endif
212 #  endif
213 
214 /* Uses filename and BHFI to fill a stat64 structure.
215  * Tries to reproduce the behaviour and quirks of MS C runtime stat().
216  */
217 static int
_g_win32_fill_statbuf_from_handle_info(const wchar_t * filename,const wchar_t * filename_target,const BY_HANDLE_FILE_INFORMATION * handle_info,struct __stat64 * statbuf)218 _g_win32_fill_statbuf_from_handle_info (const wchar_t                    *filename,
219                                         const wchar_t                    *filename_target,
220                                         const BY_HANDLE_FILE_INFORMATION *handle_info,
221                                         struct __stat64                  *statbuf)
222 {
223   wchar_t drive_letter_w = 0;
224   size_t drive_letter_size = MB_CUR_MAX;
225   char *drive_letter = _alloca (drive_letter_size);
226 
227   /* If filename (target or link) is absolute,
228    * then use the drive letter from it as-is.
229    */
230   if (filename_target != NULL &&
231       filename_target[0] != L'\0' &&
232       filename_target[1] == L':')
233     drive_letter_w = filename_target[0];
234   else if (filename[0] != L'\0' &&
235            filename[1] == L':')
236     drive_letter_w = filename[0];
237 
238   if (drive_letter_w > 0 &&
239       iswalpha (drive_letter_w) &&
240       iswascii (drive_letter_w) &&
241       wctomb (drive_letter, drive_letter_w) == 1)
242     statbuf->st_dev = toupper (drive_letter[0]) - 'A'; /* 0 means A: drive */
243   else
244     /* Otherwise use the PWD drive.
245      * Return value of 0 gives us 0 - 1 = -1,
246      * which is the "no idea" value for st_dev.
247      */
248     statbuf->st_dev = _getdrive () - 1;
249 
250   statbuf->st_rdev = statbuf->st_dev;
251   /* Theoretically, it's possible to set it for ext-FS. No idea how.
252    * Meaningless for all filesystems that Windows normally uses.
253    */
254   statbuf->st_ino = 0;
255   statbuf->st_mode = 0;
256 
257   if ((handle_info->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
258     statbuf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
259   else
260     statbuf->st_mode |= S_IFREG;
261   /* No idea what S_IFCHR means here. */
262   /* S_IFIFO is not even mentioned in MSDN */
263   /* S_IFBLK is also not mentioned */
264 
265   /* The aim here is to reproduce MS stat() behaviour,
266    * even if it's braindead.
267    */
268   statbuf->st_mode |= S_IRUSR | S_IRGRP | S_IROTH;
269   if ((handle_info->dwFileAttributes & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
270     statbuf->st_mode |= S_IWUSR | S_IWGRP | S_IWOTH;
271 
272   if (!S_ISDIR (statbuf->st_mode))
273     {
274       const wchar_t *name;
275       const wchar_t *dot = NULL;
276 
277       if (filename_target != NULL)
278         name = filename_target;
279       else
280         name = filename;
281 
282       do
283         {
284           wchar_t *last_dot = wcschr (name, L'.');
285           if (last_dot == NULL)
286             break;
287           dot = last_dot;
288           name = &last_dot[1];
289         }
290       while (TRUE);
291 
292       if ((dot != NULL &&
293           (wcsicmp (dot, L".exe") == 0 ||
294            wcsicmp (dot, L".com") == 0 ||
295            wcsicmp (dot, L".bat") == 0 ||
296            wcsicmp (dot, L".cmd") == 0)))
297         statbuf->st_mode |= S_IXUSR | S_IXGRP | S_IXOTH;
298     }
299 
300   statbuf->st_nlink = handle_info->nNumberOfLinks;
301   statbuf->st_uid = statbuf->st_gid = 0;
302   statbuf->st_size = (((guint64) handle_info->nFileSizeHigh) << 32) | handle_info->nFileSizeLow;
303   statbuf->st_ctime = _g_win32_filetime_to_unix_time (&handle_info->ftCreationTime, NULL);
304   statbuf->st_mtime = _g_win32_filetime_to_unix_time (&handle_info->ftLastWriteTime, NULL);
305   statbuf->st_atime = _g_win32_filetime_to_unix_time (&handle_info->ftLastAccessTime, NULL);
306 
307   return 0;
308 }
309 
310 /* Fills our private stat-like structure using data from
311  * a normal stat64 struct, BHFI, FSI and a reparse tag.
312  */
313 static void
_g_win32_fill_privatestat(const struct __stat64 * statbuf,const BY_HANDLE_FILE_INFORMATION * handle_info,const FILE_STANDARD_INFO * std_info,DWORD reparse_tag,GWin32PrivateStat * buf)314 _g_win32_fill_privatestat (const struct __stat64            *statbuf,
315                            const BY_HANDLE_FILE_INFORMATION *handle_info,
316                            const FILE_STANDARD_INFO         *std_info,
317                            DWORD                             reparse_tag,
318                            GWin32PrivateStat                *buf)
319 {
320   buf->st_dev = statbuf->st_dev;
321   buf->st_ino = statbuf->st_ino;
322   buf->st_mode = statbuf->st_mode;
323   buf->volume_serial = handle_info->dwVolumeSerialNumber;
324   buf->file_index = (((guint64) handle_info->nFileIndexHigh) << 32) | handle_info->nFileIndexLow;
325   buf->attributes = handle_info->dwFileAttributes;
326   buf->st_nlink = handle_info->nNumberOfLinks;
327   buf->st_size = (((guint64) handle_info->nFileSizeHigh) << 32) | handle_info->nFileSizeLow;
328   buf->allocated_size = std_info->AllocationSize.QuadPart;
329 
330   buf->reparse_tag = reparse_tag;
331 
332   buf->st_ctim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftCreationTime, &buf->st_ctim.tv_nsec);
333   buf->st_mtim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftLastWriteTime, &buf->st_mtim.tv_nsec);
334   buf->st_atim.tv_sec = _g_win32_filetime_to_unix_time (&handle_info->ftLastAccessTime, &buf->st_atim.tv_nsec);
335 }
336 
337 /* Read the link data from a symlink/mountpoint represented
338  * by the handle. Also reads reparse tag.
339  * @reparse_tag receives the tag. Can be %NULL if @buf or @alloc_buf
340  *              is non-NULL.
341  * @buf receives the link data. Can be %NULL if reparse_tag is non-%NULL.
342  *      Mutually-exclusive with @alloc_buf.
343  * @buf_size is the size of the @buf, in bytes.
344  * @alloc_buf points to a location where internally-allocated buffer
345  *            pointer will be written. That buffer receives the
346  *            link data. Mutually-exclusive with @buf.
347  * @terminate ensures that the buffer is NUL-terminated if
348  *            it isn't already. Note that this can erase useful
349  *            data if @buf is provided and @buf_size is too small.
350  *            Specifically, with @buf_size <= 2 the buffer will
351  *            receive an empty string, even if there is some
352  *            data in the reparse point.
353  * The contents of @buf or @alloc_buf are presented as-is - could
354  * be non-NUL-terminated (unless @terminate is %TRUE) or even malformed.
355  * Returns the number of bytes (!) placed into @buf or @alloc_buf,
356  * including NUL-terminator (if any).
357  *
358  * Returned value of 0 means that there's no recognizable data in the
359  * reparse point. @alloc_buf will not be allocated in that case,
360  * and @buf will be left unmodified.
361  *
362  * If @buf and @alloc_buf are %NULL, returns 0 to indicate success.
363  * Returns -1 to indicate an error, sets errno.
364  */
365 static int
_g_win32_readlink_handle_raw(HANDLE h,DWORD * reparse_tag,gunichar2 * buf,gsize buf_size,gunichar2 ** alloc_buf,gboolean terminate)366 _g_win32_readlink_handle_raw (HANDLE      h,
367                               DWORD      *reparse_tag,
368                               gunichar2  *buf,
369                               gsize       buf_size,
370                               gunichar2 **alloc_buf,
371                               gboolean    terminate)
372 {
373   DWORD error_code;
374   DWORD returned_bytes = 0;
375   BYTE *data;
376   gsize to_copy;
377   /* This is 16k. It's impossible to make DeviceIoControl() tell us
378    * the required size. NtFsControlFile() does have such a feature,
379    * but for some reason it doesn't work with CreateFile()-returned handles.
380    * The only alternative is to repeatedly call DeviceIoControl()
381    * with bigger and bigger buffers, until it succeeds.
382    * We choose to sacrifice stack space for speed.
383    */
384   BYTE max_buffer[sizeof (REPARSE_DATA_BUFFER) + MAXIMUM_REPARSE_DATA_BUFFER_SIZE] = {0,};
385   DWORD max_buffer_size = sizeof (REPARSE_DATA_BUFFER) + MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
386   REPARSE_DATA_BUFFER *rep_buf;
387 
388   g_return_val_if_fail ((buf != NULL || alloc_buf != NULL || reparse_tag != NULL) &&
389                         (buf == NULL || alloc_buf == NULL),
390                         -1);
391 
392   if (!DeviceIoControl (h, FSCTL_GET_REPARSE_POINT, NULL, 0,
393                         max_buffer,
394                         max_buffer_size,
395                         &returned_bytes, NULL))
396     {
397       error_code = GetLastError ();
398       errno = w32_error_to_errno (error_code);
399       return -1;
400     }
401 
402   rep_buf = (REPARSE_DATA_BUFFER *) max_buffer;
403 
404   if (reparse_tag != NULL)
405     *reparse_tag = rep_buf->ReparseTag;
406 
407   if (buf == NULL && alloc_buf == NULL)
408     return 0;
409 
410   if (rep_buf->ReparseTag == IO_REPARSE_TAG_SYMLINK)
411     {
412       data = &((BYTE *) rep_buf->SymbolicLinkReparseBuffer.PathBuffer)[rep_buf->SymbolicLinkReparseBuffer.SubstituteNameOffset];
413 
414       to_copy = rep_buf->SymbolicLinkReparseBuffer.SubstituteNameLength;
415     }
416   else if (rep_buf->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT)
417     {
418       data = &((BYTE *) rep_buf->MountPointReparseBuffer.PathBuffer)[rep_buf->MountPointReparseBuffer.SubstituteNameOffset];
419 
420       to_copy = rep_buf->MountPointReparseBuffer.SubstituteNameLength;
421     }
422   else
423     to_copy = 0;
424 
425   return _g_win32_copy_and_maybe_terminate (data, to_copy, buf, buf_size, alloc_buf, terminate);
426 }
427 
428 /* Read the link data from a symlink/mountpoint represented
429  * by the @filename.
430  * @filename is the name of the file.
431  * @reparse_tag receives the tag. Can be %NULL if @buf or @alloc_buf
432  *              is non-%NULL.
433  * @buf receives the link data. Mutually-exclusive with @alloc_buf.
434  * @buf_size is the size of the @buf, in bytes.
435  * @alloc_buf points to a location where internally-allocated buffer
436  *            pointer will be written. That buffer receives the
437  *            link data. Mutually-exclusive with @buf.
438  * @terminate ensures that the buffer is NUL-terminated if
439  *            it isn't already
440  * The contents of @buf or @alloc_buf are presented as-is - could
441  * be non-NUL-terminated (unless @terminate is TRUE) or even malformed.
442  * Returns the number of bytes (!) placed into @buf or @alloc_buf.
443  * Returned value of 0 means that there's no recognizable data in the
444  * reparse point. @alloc_buf will not be allocated in that case,
445  * and @buf will be left unmodified.
446  * If @buf and @alloc_buf are %NULL, returns 0 to indicate success.
447  * Returns -1 to indicate an error, sets errno.
448  */
449 static int
_g_win32_readlink_utf16_raw(const gunichar2 * filename,DWORD * reparse_tag,gunichar2 * buf,gsize buf_size,gunichar2 ** alloc_buf,gboolean terminate)450 _g_win32_readlink_utf16_raw (const gunichar2  *filename,
451                              DWORD            *reparse_tag,
452                              gunichar2        *buf,
453                              gsize             buf_size,
454                              gunichar2       **alloc_buf,
455                              gboolean          terminate)
456 {
457   HANDLE h;
458   DWORD attributes;
459   DWORD to_copy;
460   DWORD error_code;
461 
462   if ((attributes = GetFileAttributesW (filename)) == 0)
463     {
464       error_code = GetLastError ();
465       errno = w32_error_to_errno (error_code);
466       return -1;
467     }
468 
469   if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
470     {
471       errno = EINVAL;
472       return -1;
473     }
474 
475   /* To read symlink target we need to open the file as a reparse
476    * point and use DeviceIoControl() on it.
477    */
478   h = CreateFileW (filename,
479                    FILE_READ_EA,
480                    FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
481                    NULL, OPEN_EXISTING,
482                    FILE_ATTRIBUTE_NORMAL
483                    | FILE_FLAG_OPEN_REPARSE_POINT
484                    | (attributes & FILE_ATTRIBUTE_DIRECTORY ? FILE_FLAG_BACKUP_SEMANTICS : 0),
485                    NULL);
486 
487   if (h == INVALID_HANDLE_VALUE)
488     {
489       error_code = GetLastError ();
490       errno = w32_error_to_errno (error_code);
491       return -1;
492     }
493 
494   to_copy = _g_win32_readlink_handle_raw (h, reparse_tag, buf, buf_size, alloc_buf, terminate);
495 
496   CloseHandle (h);
497 
498   return to_copy;
499 }
500 
501 /* Read the link data from a symlink/mountpoint represented
502  * by a UTF-16 filename or a file handle.
503  * @filename is the name of the file. Mutually-exclusive with @file_handle.
504  * @file_handle is the handle of the file. Mutually-exclusive with @filename.
505  * @reparse_tag receives the tag. Can be %NULL if @buf or @alloc_buf
506  *              is non-%NULL.
507  * @buf receives the link data. Mutually-exclusive with @alloc_buf.
508  * @buf_size is the size of the @buf, in bytes.
509  * @alloc_buf points to a location where internally-allocated buffer
510  *            pointer will be written. That buffer receives the
511  *            link data. Mutually-exclusive with @buf.
512  * @terminate ensures that the buffer is NUL-terminated if
513  *            it isn't already
514  * The contents of @buf or @alloc_buf are adjusted
515  * (extended or nt object manager prefix is stripped),
516  * but otherwise they are presented as-is - could be non-NUL-terminated
517  * (unless @terminate is TRUE) or even malformed.
518  * Returns the number of bytes (!) placed into @buf or @alloc_buf.
519  * Returned value of 0 means that there's no recognizable data in the
520  * reparse point. @alloc_buf will not be allocated in that case,
521  * and @buf will be left unmodified.
522  * Returns -1 to indicate an error, sets errno.
523  */
524 static int
_g_win32_readlink_utf16_handle(const gunichar2 * filename,HANDLE file_handle,DWORD * reparse_tag,gunichar2 * buf,gsize buf_size,gunichar2 ** alloc_buf,gboolean terminate)525 _g_win32_readlink_utf16_handle (const gunichar2  *filename,
526                                 HANDLE            file_handle,
527                                 DWORD            *reparse_tag,
528                                 gunichar2        *buf,
529                                 gsize             buf_size,
530                                 gunichar2       **alloc_buf,
531                                 gboolean          terminate)
532 {
533   int   result;
534   gsize string_size;
535 
536   g_return_val_if_fail ((buf != NULL || alloc_buf != NULL || reparse_tag != NULL) &&
537                         (filename != NULL || file_handle != NULL) &&
538                         (buf == NULL || alloc_buf == NULL) &&
539                         (filename == NULL || file_handle == NULL),
540                         -1);
541 
542   if (filename)
543     result = _g_win32_readlink_utf16_raw (filename, reparse_tag, buf, buf_size, alloc_buf, terminate);
544   else
545     result = _g_win32_readlink_handle_raw (file_handle, reparse_tag, buf, buf_size, alloc_buf, terminate);
546 
547   if (result <= 0)
548     return result;
549 
550   /* Ensure that output is a multiple of sizeof (gunichar2),
551    * cutting any trailing partial gunichar2, if present.
552    */
553   result -= result % sizeof (gunichar2);
554 
555   if (result <= 0)
556     return result;
557 
558   /* DeviceIoControl () tends to return filenames as NT Object Manager
559    * names , i.e. "\\??\\C:\\foo\\bar".
560    * Remove the leading 4-byte "\\??\\" prefix, as glib (as well as many W32 API
561    * functions) is unprepared to deal with it. Unless it has no 'x:' drive
562    * letter part after the prefix, in which case we leave everything
563    * as-is, because the path could be "\\??\\Volume{GUID}" - stripping
564    * the prefix will allow it to be confused with relative links
565    * targeting "Volume{GUID}".
566    */
567   string_size = result / sizeof (gunichar2);
568   _g_win32_strip_extended_ntobjm_prefix (buf ? buf : *alloc_buf, &string_size);
569 
570   return string_size * sizeof (gunichar2);
571 }
572 
573 /* Works like stat() or lstat(), depending on the value of @for_symlink,
574  * but accepts filename in UTF-16 and fills our custom stat structure.
575  * The @filename must not have trailing slashes.
576  */
577 static int
_g_win32_stat_utf16_no_trailing_slashes(const gunichar2 * filename,GWin32PrivateStat * buf,gboolean for_symlink)578 _g_win32_stat_utf16_no_trailing_slashes (const gunichar2    *filename,
579                                          GWin32PrivateStat  *buf,
580                                          gboolean            for_symlink)
581 {
582   struct __stat64 statbuf;
583   BY_HANDLE_FILE_INFORMATION handle_info;
584   FILE_STANDARD_INFO std_info;
585   gboolean is_symlink = FALSE;
586   wchar_t *filename_target = NULL;
587   DWORD immediate_attributes;
588   DWORD open_flags;
589   gboolean is_directory;
590   DWORD reparse_tag = 0;
591   DWORD error_code;
592   BOOL succeeded_so_far;
593   HANDLE file_handle;
594 
595   immediate_attributes = GetFileAttributesW (filename);
596 
597   if (immediate_attributes == INVALID_FILE_ATTRIBUTES)
598     {
599       error_code = GetLastError ();
600       errno = w32_error_to_errno (error_code);
601 
602       return -1;
603     }
604 
605   is_symlink = (immediate_attributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT;
606   is_directory = (immediate_attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
607 
608   open_flags = FILE_ATTRIBUTE_NORMAL;
609 
610   if (for_symlink && is_symlink)
611     open_flags |= FILE_FLAG_OPEN_REPARSE_POINT;
612 
613   if (is_directory)
614     open_flags |= FILE_FLAG_BACKUP_SEMANTICS;
615 
616   file_handle = CreateFileW (filename, FILE_READ_ATTRIBUTES | FILE_READ_EA,
617                              FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
618                              NULL, OPEN_EXISTING,
619                              open_flags,
620                              NULL);
621 
622   if (file_handle == INVALID_HANDLE_VALUE)
623     {
624       error_code = GetLastError ();
625       errno = w32_error_to_errno (error_code);
626       return -1;
627     }
628 
629   succeeded_so_far = GetFileInformationByHandle (file_handle,
630                                                  &handle_info);
631   error_code = GetLastError ();
632 
633   if (succeeded_so_far)
634     {
635       succeeded_so_far = GetFileInformationByHandleEx (file_handle,
636                                                        FileStandardInfo,
637                                                        &std_info,
638                                                        sizeof (std_info));
639       error_code = GetLastError ();
640     }
641 
642   if (!succeeded_so_far)
643     {
644       CloseHandle (file_handle);
645       errno = w32_error_to_errno (error_code);
646       return -1;
647     }
648 
649   /* It's tempting to use GetFileInformationByHandleEx(FileAttributeTagInfo),
650    * but it always reports that the ReparseTag is 0.
651    * We already have a handle open for symlink, use that.
652    * For the target we have to specify a filename, and the function
653    * will open another handle internally.
654    */
655   if (is_symlink &&
656       _g_win32_readlink_utf16_handle (for_symlink ? NULL : filename,
657                                       for_symlink ? file_handle : NULL,
658                                       &reparse_tag,
659                                       NULL, 0,
660                                       for_symlink ? NULL : &filename_target,
661                                       TRUE) < 0)
662     {
663       CloseHandle (file_handle);
664       return -1;
665     }
666 
667   CloseHandle (file_handle);
668 
669   _g_win32_fill_statbuf_from_handle_info (filename,
670                                           filename_target,
671                                           &handle_info,
672                                           &statbuf);
673   g_free (filename_target);
674   _g_win32_fill_privatestat (&statbuf,
675                              &handle_info,
676                              &std_info,
677                              reparse_tag,
678                              buf);
679 
680   return 0;
681 }
682 
683 /* Works like fstat(), but fills our custom stat structure. */
684 static int
_g_win32_stat_fd(int fd,GWin32PrivateStat * buf)685 _g_win32_stat_fd (int                 fd,
686                   GWin32PrivateStat  *buf)
687 {
688   HANDLE file_handle;
689   gboolean succeeded_so_far;
690   DWORD error_code;
691   struct __stat64 statbuf;
692   BY_HANDLE_FILE_INFORMATION handle_info;
693   FILE_STANDARD_INFO std_info;
694   DWORD reparse_tag = 0;
695   gboolean is_symlink = FALSE;
696 
697   file_handle = (HANDLE) _get_osfhandle (fd);
698 
699   if (file_handle == INVALID_HANDLE_VALUE)
700     return -1;
701 
702   succeeded_so_far = GetFileInformationByHandle (file_handle,
703                                                  &handle_info);
704   error_code = GetLastError ();
705 
706   if (succeeded_so_far)
707     {
708       succeeded_so_far = GetFileInformationByHandleEx (file_handle,
709                                                        FileStandardInfo,
710                                                        &std_info,
711                                                        sizeof (std_info));
712       error_code = GetLastError ();
713     }
714 
715   if (!succeeded_so_far)
716     {
717       errno = w32_error_to_errno (error_code);
718       return -1;
719     }
720 
721   is_symlink = (handle_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) == FILE_ATTRIBUTE_REPARSE_POINT;
722 
723   if (is_symlink &&
724       _g_win32_readlink_handle_raw (file_handle, &reparse_tag, NULL, 0, NULL, FALSE) < 0)
725     return -1;
726 
727   if (_fstat64 (fd, &statbuf) != 0)
728     return -1;
729 
730   _g_win32_fill_privatestat (&statbuf,
731                              &handle_info,
732                              &std_info,
733                              reparse_tag,
734                              buf);
735 
736   return 0;
737 }
738 
739 /* Works like stat() or lstat(), depending on the value of @for_symlink,
740  * but accepts filename in UTF-8 and fills our custom stat structure.
741  */
742 static int
_g_win32_stat_utf8(const gchar * filename,GWin32PrivateStat * buf,gboolean for_symlink)743 _g_win32_stat_utf8 (const gchar       *filename,
744                     GWin32PrivateStat *buf,
745                     gboolean           for_symlink)
746 {
747   wchar_t *wfilename;
748   int result;
749   gsize len;
750 
751   if (filename == NULL)
752     {
753       errno = EINVAL;
754       return -1;
755     }
756 
757   len = strlen (filename);
758 
759   while (len > 0 && G_IS_DIR_SEPARATOR (filename[len - 1]))
760     len--;
761 
762   if (len <= 0 ||
763       (g_path_is_absolute (filename) && len <= g_path_skip_root (filename) - filename))
764     len = strlen (filename);
765 
766   wfilename = g_utf8_to_utf16 (filename, len, NULL, NULL, NULL);
767 
768   if (wfilename == NULL)
769     {
770       errno = EINVAL;
771       return -1;
772     }
773 
774   result = _g_win32_stat_utf16_no_trailing_slashes (wfilename, buf, for_symlink);
775 
776   g_free (wfilename);
777 
778   return result;
779 }
780 
781 /* Works like stat(), but accepts filename in UTF-8
782  * and fills our custom stat structure.
783  */
784 int
g_win32_stat_utf8(const gchar * filename,GWin32PrivateStat * buf)785 g_win32_stat_utf8 (const gchar       *filename,
786                    GWin32PrivateStat *buf)
787 {
788   return _g_win32_stat_utf8 (filename, buf, FALSE);
789 }
790 
791 /* Works like lstat(), but accepts filename in UTF-8
792  * and fills our custom stat structure.
793  */
794 int
g_win32_lstat_utf8(const gchar * filename,GWin32PrivateStat * buf)795 g_win32_lstat_utf8 (const gchar       *filename,
796                     GWin32PrivateStat *buf)
797 {
798   return _g_win32_stat_utf8 (filename, buf, TRUE);
799 }
800 
801 /* Works like fstat(), but accepts filename in UTF-8
802  * and fills our custom stat structure.
803  */
804 int
g_win32_fstat(int fd,GWin32PrivateStat * buf)805 g_win32_fstat (int                fd,
806                GWin32PrivateStat *buf)
807 {
808   return _g_win32_stat_fd (fd, buf);
809 }
810 
811 /**
812  * g_win32_readlink_utf8:
813  * @filename: (type filename): a pathname in UTF-8
814  * @buf: (array length=buf_size) : a buffer to receive the reparse point
815  *                                 target path. Mutually-exclusive
816  *                                 with @alloc_buf.
817  * @buf_size: size of the @buf, in bytes
818  * @alloc_buf: points to a location where internally-allocated buffer
819  *             pointer will be written. That buffer receives the
820  *             link data. Mutually-exclusive with @buf.
821  * @terminate: ensures that the buffer is NUL-terminated if
822  *             it isn't already. If %FALSE, the returned string
823  *             might not be NUL-terminated (depends entirely on
824  *             what the contents of the filesystem are).
825  *
826  * Tries to read the reparse point indicated by @filename, filling
827  * @buf or @alloc_buf with the path that the reparse point redirects to.
828  * The path will be UTF-8-encoded, and an extended path prefix
829  * or a NT object manager prefix will be removed from it, if
830  * possible, but otherwise the path is returned as-is. Specifically,
831  * it could be a "\\\\Volume{GUID}\\" path. It also might use
832  * backslashes as path separators.
833  *
834  * Returns: -1 on error (sets errno), 0 if there's no (recognizable)
835  * path in the reparse point (@alloc_buf will not be allocated in that case,
836  * and @buf will be left unmodified),
837  * or the number of bytes placed into @buf otherwise,
838  * including NUL-terminator (if present or if @terminate is TRUE).
839  * The buffer returned via @alloc_buf should be freed with g_free().
840  *
841  * Since: 2.60
842  */
843 int
g_win32_readlink_utf8(const gchar * filename,gchar * buf,gsize buf_size,gchar ** alloc_buf,gboolean terminate)844 g_win32_readlink_utf8 (const gchar  *filename,
845                        gchar        *buf,
846                        gsize         buf_size,
847                        gchar       **alloc_buf,
848                        gboolean      terminate)
849 {
850   wchar_t *wfilename;
851   int result;
852   wchar_t *buf_utf16;
853   glong tmp_len;
854   gchar *tmp;
855 
856   g_return_val_if_fail ((buf != NULL || alloc_buf != NULL) &&
857                         (buf == NULL || alloc_buf == NULL),
858                         -1);
859 
860   wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
861 
862   if (wfilename == NULL)
863     {
864       errno = EINVAL;
865       return -1;
866     }
867 
868   result = _g_win32_readlink_utf16_handle (wfilename, NULL, NULL,
869                                            NULL, 0, &buf_utf16, terminate);
870 
871   g_free (wfilename);
872 
873   if (result <= 0)
874     return result;
875 
876   tmp = g_utf16_to_utf8 (buf_utf16,
877                          result / sizeof (gunichar2),
878                          NULL,
879                          &tmp_len,
880                          NULL);
881 
882   g_free (buf_utf16);
883 
884   if (tmp == NULL)
885     {
886       errno = EINVAL;
887       return -1;
888     }
889 
890   if (alloc_buf)
891     {
892       *alloc_buf = tmp;
893       return tmp_len;
894     }
895 
896   if (tmp_len > buf_size)
897     tmp_len = buf_size;
898 
899   memcpy (buf, tmp, tmp_len);
900   g_free (tmp);
901 
902   return tmp_len;
903 }
904 
905 #endif
906 
907 /**
908  * g_access:
909  * @filename: (type filename): a pathname in the GLib file name encoding
910  *     (UTF-8 on Windows)
911  * @mode: as in access()
912  *
913  * A wrapper for the POSIX access() function. This function is used to
914  * test a pathname for one or several of read, write or execute
915  * permissions, or just existence.
916  *
917  * On Windows, the file protection mechanism is not at all POSIX-like,
918  * and the underlying function in the C library only checks the
919  * FAT-style READONLY attribute, and does not look at the ACL of a
920  * file at all. This function is this in practise almost useless on
921  * Windows. Software that needs to handle file permissions on Windows
922  * more exactly should use the Win32 API.
923  *
924  * See your C library manual for more details about access().
925  *
926  * Returns: zero if the pathname refers to an existing file system
927  *     object that has all the tested permissions, or -1 otherwise
928  *     or on error.
929  *
930  * Since: 2.8
931  */
932 int
g_access(const gchar * filename,int mode)933 g_access (const gchar *filename,
934 	  int          mode)
935 {
936 #ifdef G_OS_WIN32
937   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
938   int retval;
939   int save_errno;
940 
941   if (wfilename == NULL)
942     {
943       errno = EINVAL;
944       return -1;
945     }
946 
947 #ifndef X_OK
948 #define X_OK 1
949 #endif
950 
951   retval = _waccess (wfilename, mode & ~X_OK);
952   save_errno = errno;
953 
954   g_free (wfilename);
955 
956   errno = save_errno;
957   return retval;
958 #else
959   return access (filename, mode);
960 #endif
961 }
962 
963 /**
964  * g_chmod:
965  * @filename: (type filename): a pathname in the GLib file name encoding
966  *     (UTF-8 on Windows)
967  * @mode: as in chmod()
968  *
969  * A wrapper for the POSIX chmod() function. The chmod() function is
970  * used to set the permissions of a file system object.
971  *
972  * On Windows the file protection mechanism is not at all POSIX-like,
973  * and the underlying chmod() function in the C library just sets or
974  * clears the FAT-style READONLY attribute. It does not touch any
975  * ACL. Software that needs to manage file permissions on Windows
976  * exactly should use the Win32 API.
977  *
978  * See your C library manual for more details about chmod().
979  *
980  * Returns: 0 if the operation succeeded, -1 on error
981  *
982  * Since: 2.8
983  */
984 int
g_chmod(const gchar * filename,int mode)985 g_chmod (const gchar *filename,
986 	 int          mode)
987 {
988 #ifdef G_OS_WIN32
989   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
990   int retval;
991   int save_errno;
992 
993   if (wfilename == NULL)
994     {
995       errno = EINVAL;
996       return -1;
997     }
998 
999   retval = _wchmod (wfilename, mode);
1000   save_errno = errno;
1001 
1002   g_free (wfilename);
1003 
1004   errno = save_errno;
1005   return retval;
1006 #else
1007   return chmod (filename, mode);
1008 #endif
1009 }
1010 /**
1011  * g_open:
1012  * @filename: (type filename): a pathname in the GLib file name encoding
1013  *     (UTF-8 on Windows)
1014  * @flags: as in open()
1015  * @mode: as in open()
1016  *
1017  * A wrapper for the POSIX open() function. The open() function is
1018  * used to convert a pathname into a file descriptor.
1019  *
1020  * On POSIX systems file descriptors are implemented by the operating
1021  * system. On Windows, it's the C library that implements open() and
1022  * file descriptors. The actual Win32 API for opening files is quite
1023  * different, see MSDN documentation for CreateFile(). The Win32 API
1024  * uses file handles, which are more randomish integers, not small
1025  * integers like file descriptors.
1026  *
1027  * Because file descriptors are specific to the C library on Windows,
1028  * the file descriptor returned by this function makes sense only to
1029  * functions in the same C library. Thus if the GLib-using code uses a
1030  * different C library than GLib does, the file descriptor returned by
1031  * this function cannot be passed to C library functions like write()
1032  * or read().
1033  *
1034  * See your C library manual for more details about open().
1035  *
1036  * Returns: a new file descriptor, or -1 if an error occurred.
1037  *     The return value can be used exactly like the return value
1038  *     from open().
1039  *
1040  * Since: 2.6
1041  */
1042 int
g_open(const gchar * filename,int flags,int mode)1043 g_open (const gchar *filename,
1044 	int          flags,
1045 	int          mode)
1046 {
1047 #ifdef G_OS_WIN32
1048   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1049   int retval;
1050   int save_errno;
1051 
1052   if (wfilename == NULL)
1053     {
1054       errno = EINVAL;
1055       return -1;
1056     }
1057 
1058   retval = _wopen (wfilename, flags, mode);
1059   save_errno = errno;
1060 
1061   g_free (wfilename);
1062 
1063   errno = save_errno;
1064   return retval;
1065 #else
1066   int fd;
1067   do
1068     fd = open (filename, flags, mode);
1069   while (G_UNLIKELY (fd == -1 && errno == EINTR));
1070   return fd;
1071 #endif
1072 }
1073 
1074 /**
1075  * g_creat:
1076  * @filename: (type filename): a pathname in the GLib file name encoding
1077  *     (UTF-8 on Windows)
1078  * @mode: as in creat()
1079  *
1080  * A wrapper for the POSIX creat() function. The creat() function is
1081  * used to convert a pathname into a file descriptor, creating a file
1082  * if necessary.
1083  *
1084  * On POSIX systems file descriptors are implemented by the operating
1085  * system. On Windows, it's the C library that implements creat() and
1086  * file descriptors. The actual Windows API for opening files is
1087  * different, see MSDN documentation for CreateFile(). The Win32 API
1088  * uses file handles, which are more randomish integers, not small
1089  * integers like file descriptors.
1090  *
1091  * Because file descriptors are specific to the C library on Windows,
1092  * the file descriptor returned by this function makes sense only to
1093  * functions in the same C library. Thus if the GLib-using code uses a
1094  * different C library than GLib does, the file descriptor returned by
1095  * this function cannot be passed to C library functions like write()
1096  * or read().
1097  *
1098  * See your C library manual for more details about creat().
1099  *
1100  * Returns: a new file descriptor, or -1 if an error occurred.
1101  *     The return value can be used exactly like the return value
1102  *     from creat().
1103  *
1104  * Since: 2.8
1105  */
1106 int
g_creat(const gchar * filename,int mode)1107 g_creat (const gchar *filename,
1108 	 int          mode)
1109 {
1110 #ifdef G_OS_WIN32
1111   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1112   int retval;
1113   int save_errno;
1114 
1115   if (wfilename == NULL)
1116     {
1117       errno = EINVAL;
1118       return -1;
1119     }
1120 
1121   retval = _wcreat (wfilename, mode);
1122   save_errno = errno;
1123 
1124   g_free (wfilename);
1125 
1126   errno = save_errno;
1127   return retval;
1128 #else
1129   return creat (filename, mode);
1130 #endif
1131 }
1132 
1133 /**
1134  * g_rename:
1135  * @oldfilename: (type filename): a pathname in the GLib file name encoding
1136  *     (UTF-8 on Windows)
1137  * @newfilename: (type filename): a pathname in the GLib file name encoding
1138  *
1139  * A wrapper for the POSIX rename() function. The rename() function
1140  * renames a file, moving it between directories if required.
1141  *
1142  * See your C library manual for more details about how rename() works
1143  * on your system. It is not possible in general on Windows to rename
1144  * a file that is open to some process.
1145  *
1146  * Returns: 0 if the renaming succeeded, -1 if an error occurred
1147  *
1148  * Since: 2.6
1149  */
1150 int
g_rename(const gchar * oldfilename,const gchar * newfilename)1151 g_rename (const gchar *oldfilename,
1152 	  const gchar *newfilename)
1153 {
1154 #ifdef G_OS_WIN32
1155   wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
1156   wchar_t *wnewfilename;
1157   int retval;
1158   int save_errno = 0;
1159 
1160   if (woldfilename == NULL)
1161     {
1162       errno = EINVAL;
1163       return -1;
1164     }
1165 
1166   wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
1167 
1168   if (wnewfilename == NULL)
1169     {
1170       g_free (woldfilename);
1171       errno = EINVAL;
1172       return -1;
1173     }
1174 
1175   if (MoveFileExW (woldfilename, wnewfilename, MOVEFILE_REPLACE_EXISTING))
1176     retval = 0;
1177   else
1178     {
1179       retval = -1;
1180       save_errno = w32_error_to_errno (GetLastError ());
1181     }
1182 
1183   g_free (woldfilename);
1184   g_free (wnewfilename);
1185 
1186   errno = save_errno;
1187   return retval;
1188 #else
1189   return rename (oldfilename, newfilename);
1190 #endif
1191 }
1192 
1193 /**
1194  * g_mkdir:
1195  * @filename: (type filename): a pathname in the GLib file name encoding
1196  *     (UTF-8 on Windows)
1197  * @mode: permissions to use for the newly created directory
1198  *
1199  * A wrapper for the POSIX mkdir() function. The mkdir() function
1200  * attempts to create a directory with the given name and permissions.
1201  * The mode argument is ignored on Windows.
1202  *
1203  * See your C library manual for more details about mkdir().
1204  *
1205  * Returns: 0 if the directory was successfully created, -1 if an error
1206  *    occurred
1207  *
1208  * Since: 2.6
1209  */
1210 int
g_mkdir(const gchar * filename,int mode)1211 g_mkdir (const gchar *filename,
1212 	 int          mode)
1213 {
1214 #ifdef G_OS_WIN32
1215   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1216   int retval;
1217   int save_errno;
1218 
1219   if (wfilename == NULL)
1220     {
1221       errno = EINVAL;
1222       return -1;
1223     }
1224 
1225   retval = _wmkdir (wfilename);
1226   save_errno = errno;
1227 
1228   g_free (wfilename);
1229 
1230   errno = save_errno;
1231   return retval;
1232 #else
1233   return mkdir (filename, mode);
1234 #endif
1235 }
1236 
1237 /**
1238  * g_chdir:
1239  * @path: (type filename): a pathname in the GLib file name encoding
1240  *     (UTF-8 on Windows)
1241  *
1242  * A wrapper for the POSIX chdir() function. The function changes the
1243  * current directory of the process to @path.
1244  *
1245  * See your C library manual for more details about chdir().
1246  *
1247  * Returns: 0 on success, -1 if an error occurred.
1248  *
1249  * Since: 2.8
1250  */
1251 int
g_chdir(const gchar * path)1252 g_chdir (const gchar *path)
1253 {
1254 #ifdef G_OS_WIN32
1255   wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
1256   int retval;
1257   int save_errno;
1258 
1259   if (wpath == NULL)
1260     {
1261       errno = EINVAL;
1262       return -1;
1263     }
1264 
1265   retval = _wchdir (wpath);
1266   save_errno = errno;
1267 
1268   g_free (wpath);
1269 
1270   errno = save_errno;
1271   return retval;
1272 #else
1273   return chdir (path);
1274 #endif
1275 }
1276 
1277 /**
1278  * GStatBuf:
1279  *
1280  * A type corresponding to the appropriate struct type for the stat()
1281  * system call, depending on the platform and/or compiler being used.
1282  *
1283  * See g_stat() for more information.
1284  */
1285 /**
1286  * g_stat:
1287  * @filename: (type filename): a pathname in the GLib file name encoding
1288  *     (UTF-8 on Windows)
1289  * @buf: a pointer to a stat struct, which will be filled with the file
1290  *     information
1291  *
1292  * A wrapper for the POSIX stat() function. The stat() function
1293  * returns information about a file. On Windows the stat() function in
1294  * the C library checks only the FAT-style READONLY attribute and does
1295  * not look at the ACL at all. Thus on Windows the protection bits in
1296  * the @st_mode field are a fabrication of little use.
1297  *
1298  * On Windows the Microsoft C libraries have several variants of the
1299  * stat struct and stat() function with names like _stat(), _stat32(),
1300  * _stat32i64() and _stat64i32(). The one used here is for 32-bit code
1301  * the one with 32-bit size and time fields, specifically called _stat32().
1302  *
1303  * In Microsoft's compiler, by default struct stat means one with
1304  * 64-bit time fields while in MinGW struct stat is the legacy one
1305  * with 32-bit fields. To hopefully clear up this messs, the gstdio.h
1306  * header defines a type #GStatBuf which is the appropriate struct type
1307  * depending on the platform and/or compiler being used. On POSIX it
1308  * is just struct stat, but note that even on POSIX platforms, stat()
1309  * might be a macro.
1310  *
1311  * See your C library manual for more details about stat().
1312  *
1313  * Returns: 0 if the information was successfully retrieved,
1314  *     -1 if an error occurred
1315  *
1316  * Since: 2.6
1317  */
1318 int
g_stat(const gchar * filename,GStatBuf * buf)1319 g_stat (const gchar *filename,
1320 	GStatBuf    *buf)
1321 {
1322 #ifdef G_OS_WIN32
1323   GWin32PrivateStat w32_buf;
1324   int retval = g_win32_stat_utf8 (filename, &w32_buf);
1325 
1326   buf->st_dev = w32_buf.st_dev;
1327   buf->st_ino = w32_buf.st_ino;
1328   buf->st_mode = w32_buf.st_mode;
1329   buf->st_nlink = w32_buf.st_nlink;
1330   buf->st_uid = w32_buf.st_uid;
1331   buf->st_gid = w32_buf.st_gid;
1332   buf->st_rdev = w32_buf.st_dev;
1333   buf->st_size = w32_buf.st_size;
1334   buf->st_atime = w32_buf.st_atim.tv_sec;
1335   buf->st_mtime = w32_buf.st_mtim.tv_sec;
1336   buf->st_ctime = w32_buf.st_ctim.tv_sec;
1337 
1338   return retval;
1339 #else
1340   return stat (filename, buf);
1341 #endif
1342 }
1343 
1344 /**
1345  * g_lstat:
1346  * @filename: (type filename): a pathname in the GLib file name encoding
1347  *     (UTF-8 on Windows)
1348  * @buf: a pointer to a stat struct, which will be filled with the file
1349  *     information
1350  *
1351  * A wrapper for the POSIX lstat() function. The lstat() function is
1352  * like stat() except that in the case of symbolic links, it returns
1353  * information about the symbolic link itself and not the file that it
1354  * refers to. If the system does not support symbolic links g_lstat()
1355  * is identical to g_stat().
1356  *
1357  * See your C library manual for more details about lstat().
1358  *
1359  * Returns: 0 if the information was successfully retrieved,
1360  *     -1 if an error occurred
1361  *
1362  * Since: 2.6
1363  */
1364 int
g_lstat(const gchar * filename,GStatBuf * buf)1365 g_lstat (const gchar *filename,
1366 	 GStatBuf    *buf)
1367 {
1368 #ifdef HAVE_LSTAT
1369   /* This can't be Win32, so don't do the widechar dance. */
1370   return lstat (filename, buf);
1371 #elif defined (G_OS_WIN32)
1372   GWin32PrivateStat w32_buf;
1373   int retval = g_win32_lstat_utf8 (filename, &w32_buf);
1374 
1375   buf->st_dev = w32_buf.st_dev;
1376   buf->st_ino = w32_buf.st_ino;
1377   buf->st_mode = w32_buf.st_mode;
1378   buf->st_nlink = w32_buf.st_nlink;
1379   buf->st_uid = w32_buf.st_uid;
1380   buf->st_gid = w32_buf.st_gid;
1381   buf->st_rdev = w32_buf.st_dev;
1382   buf->st_size = w32_buf.st_size;
1383   buf->st_atime = w32_buf.st_atim.tv_sec;
1384   buf->st_mtime = w32_buf.st_mtim.tv_sec;
1385   buf->st_ctime = w32_buf.st_ctim.tv_sec;
1386 
1387   return retval;
1388 #else
1389   return g_stat (filename, buf);
1390 #endif
1391 }
1392 
1393 /**
1394  * g_unlink:
1395  * @filename: (type filename): a pathname in the GLib file name encoding
1396  *     (UTF-8 on Windows)
1397  *
1398  * A wrapper for the POSIX unlink() function. The unlink() function
1399  * deletes a name from the filesystem. If this was the last link to the
1400  * file and no processes have it opened, the diskspace occupied by the
1401  * file is freed.
1402  *
1403  * See your C library manual for more details about unlink(). Note
1404  * that on Windows, it is in general not possible to delete files that
1405  * are open to some process, or mapped into memory.
1406  *
1407  * Returns: 0 if the name was successfully deleted, -1 if an error
1408  *    occurred
1409  *
1410  * Since: 2.6
1411  */
1412 int
g_unlink(const gchar * filename)1413 g_unlink (const gchar *filename)
1414 {
1415 #ifdef G_OS_WIN32
1416   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1417   int retval;
1418   int save_errno;
1419 
1420   if (wfilename == NULL)
1421     {
1422       errno = EINVAL;
1423       return -1;
1424     }
1425 
1426   retval = _wunlink (wfilename);
1427   save_errno = errno;
1428 
1429   g_free (wfilename);
1430 
1431   errno = save_errno;
1432   return retval;
1433 #else
1434   return unlink (filename);
1435 #endif
1436 }
1437 
1438 /**
1439  * g_remove:
1440  * @filename: (type filename): a pathname in the GLib file name encoding
1441  *     (UTF-8 on Windows)
1442  *
1443  * A wrapper for the POSIX remove() function. The remove() function
1444  * deletes a name from the filesystem.
1445  *
1446  * See your C library manual for more details about how remove() works
1447  * on your system. On Unix, remove() removes also directories, as it
1448  * calls unlink() for files and rmdir() for directories. On Windows,
1449  * although remove() in the C library only works for files, this
1450  * function tries first remove() and then if that fails rmdir(), and
1451  * thus works for both files and directories. Note however, that on
1452  * Windows, it is in general not possible to remove a file that is
1453  * open to some process, or mapped into memory.
1454  *
1455  * If this function fails on Windows you can't infer too much from the
1456  * errno value. rmdir() is tried regardless of what caused remove() to
1457  * fail. Any errno value set by remove() will be overwritten by that
1458  * set by rmdir().
1459  *
1460  * Returns: 0 if the file was successfully removed, -1 if an error
1461  *    occurred
1462  *
1463  * Since: 2.6
1464  */
1465 int
g_remove(const gchar * filename)1466 g_remove (const gchar *filename)
1467 {
1468 #ifdef G_OS_WIN32
1469   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1470   int retval;
1471   int save_errno;
1472 
1473   if (wfilename == NULL)
1474     {
1475       errno = EINVAL;
1476       return -1;
1477     }
1478 
1479   retval = _wremove (wfilename);
1480   if (retval == -1)
1481     retval = _wrmdir (wfilename);
1482   save_errno = errno;
1483 
1484   g_free (wfilename);
1485 
1486   errno = save_errno;
1487   return retval;
1488 #else
1489   return remove (filename);
1490 #endif
1491 }
1492 
1493 /**
1494  * g_rmdir:
1495  * @filename: (type filename): a pathname in the GLib file name encoding
1496  *     (UTF-8 on Windows)
1497  *
1498  * A wrapper for the POSIX rmdir() function. The rmdir() function
1499  * deletes a directory from the filesystem.
1500  *
1501  * See your C library manual for more details about how rmdir() works
1502  * on your system.
1503  *
1504  * Returns: 0 if the directory was successfully removed, -1 if an error
1505  *    occurred
1506  *
1507  * Since: 2.6
1508  */
1509 int
g_rmdir(const gchar * filename)1510 g_rmdir (const gchar *filename)
1511 {
1512 #ifdef G_OS_WIN32
1513   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1514   int retval;
1515   int save_errno;
1516 
1517   if (wfilename == NULL)
1518     {
1519       errno = EINVAL;
1520       return -1;
1521     }
1522 
1523   retval = _wrmdir (wfilename);
1524   save_errno = errno;
1525 
1526   g_free (wfilename);
1527 
1528   errno = save_errno;
1529   return retval;
1530 #else
1531   return rmdir (filename);
1532 #endif
1533 }
1534 
1535 /**
1536  * g_fopen:
1537  * @filename: (type filename): a pathname in the GLib file name encoding
1538  *     (UTF-8 on Windows)
1539  * @mode: a string describing the mode in which the file should be opened
1540  *
1541  * A wrapper for the stdio `fopen()` function. The `fopen()` function
1542  * opens a file and associates a new stream with it.
1543  *
1544  * Because file descriptors are specific to the C library on Windows,
1545  * and a file descriptor is part of the `FILE` struct, the `FILE*` returned
1546  * by this function makes sense only to functions in the same C library.
1547  * Thus if the GLib-using code uses a different C library than GLib does,
1548  * the FILE* returned by this function cannot be passed to C library
1549  * functions like `fprintf()` or `fread()`.
1550  *
1551  * See your C library manual for more details about `fopen()`.
1552  *
1553  * As `close()` and `fclose()` are part of the C library, this implies that it is
1554  * currently impossible to close a file if the application C library and the C library
1555  * used by GLib are different. Convenience functions like g_file_set_contents_full()
1556  * avoid this problem.
1557  *
1558  * Returns: A `FILE*` if the file was successfully opened, or %NULL if
1559  *     an error occurred
1560  *
1561  * Since: 2.6
1562  */
1563 FILE *
g_fopen(const gchar * filename,const gchar * mode)1564 g_fopen (const gchar *filename,
1565 	 const gchar *mode)
1566 {
1567 #ifdef G_OS_WIN32
1568   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1569   wchar_t *wmode;
1570   FILE *retval;
1571   int save_errno;
1572 
1573   if (wfilename == NULL)
1574     {
1575       errno = EINVAL;
1576       return NULL;
1577     }
1578 
1579   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
1580 
1581   if (wmode == NULL)
1582     {
1583       g_free (wfilename);
1584       errno = EINVAL;
1585       return NULL;
1586     }
1587 
1588   _g_win32_fix_mode (wmode);
1589   retval = _wfopen (wfilename, wmode);
1590   save_errno = errno;
1591 
1592   g_free (wfilename);
1593   g_free (wmode);
1594 
1595   errno = save_errno;
1596   return retval;
1597 #else
1598   return fopen (filename, mode);
1599 #endif
1600 }
1601 
1602 /**
1603  * g_freopen:
1604  * @filename: (type filename): a pathname in the GLib file name encoding
1605  *     (UTF-8 on Windows)
1606  * @mode: a string describing the mode in which the file should be  opened
1607  * @stream: (nullable): an existing stream which will be reused, or %NULL
1608  *
1609  * A wrapper for the POSIX freopen() function. The freopen() function
1610  * opens a file and associates it with an existing stream.
1611  *
1612  * See your C library manual for more details about freopen().
1613  *
1614  * Returns: A FILE* if the file was successfully opened, or %NULL if
1615  *     an error occurred.
1616  *
1617  * Since: 2.6
1618  */
1619 FILE *
g_freopen(const gchar * filename,const gchar * mode,FILE * stream)1620 g_freopen (const gchar *filename,
1621 	   const gchar *mode,
1622 	   FILE        *stream)
1623 {
1624 #ifdef G_OS_WIN32
1625   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1626   wchar_t *wmode;
1627   FILE *retval;
1628   int save_errno;
1629 
1630   if (wfilename == NULL)
1631     {
1632       errno = EINVAL;
1633       return NULL;
1634     }
1635 
1636   wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
1637 
1638   if (wmode == NULL)
1639     {
1640       g_free (wfilename);
1641       errno = EINVAL;
1642       return NULL;
1643     }
1644 
1645   _g_win32_fix_mode (wmode);
1646   retval = _wfreopen (wfilename, wmode, stream);
1647   save_errno = errno;
1648 
1649   g_free (wfilename);
1650   g_free (wmode);
1651 
1652   errno = save_errno;
1653   return retval;
1654 #else
1655   return freopen (filename, mode, stream);
1656 #endif
1657 }
1658 
1659 /**
1660  * g_fsync:
1661  * @fd: a file descriptor
1662  *
1663  * A wrapper for the POSIX `fsync()` function. On Windows, `_commit()` will be
1664  * used. On macOS, `fcntl(F_FULLFSYNC)` will be used.
1665  * The `fsync()` function is used to synchronize a file's in-core
1666  * state with that of the disk.
1667  *
1668  * This wrapper will handle retrying on `EINTR`.
1669  *
1670  * See the C library manual for more details about fsync().
1671  *
1672  * Returns: 0 on success, or -1 if an error occurred.
1673  * The return value can be used exactly like the return value from fsync().
1674  *
1675  * Since: 2.64
1676  */
1677 gint
g_fsync(gint fd)1678 g_fsync (gint fd)
1679 {
1680 #ifdef G_OS_WIN32
1681   return _commit (fd);
1682 #elif defined(HAVE_FSYNC) || defined(HAVE_FCNTL_F_FULLFSYNC)
1683   int retval;
1684   do
1685 #ifdef HAVE_FCNTL_F_FULLFSYNC
1686     retval = fcntl (fd, F_FULLFSYNC, 0);
1687 #else
1688     retval = fsync (fd);
1689 #endif
1690   while (G_UNLIKELY (retval < 0 && errno == EINTR));
1691   return retval;
1692 #else
1693   return 0;
1694 #endif
1695 }
1696 
1697 /**
1698  * g_utime:
1699  * @filename: (type filename): a pathname in the GLib file name encoding
1700  *     (UTF-8 on Windows)
1701  * @utb: a pointer to a struct utimbuf.
1702  *
1703  * A wrapper for the POSIX utime() function. The utime() function
1704  * sets the access and modification timestamps of a file.
1705  *
1706  * See your C library manual for more details about how utime() works
1707  * on your system.
1708  *
1709  * Returns: 0 if the operation was successful, -1 if an error occurred
1710  *
1711  * Since: 2.18
1712  */
1713 int
g_utime(const gchar * filename,struct utimbuf * utb)1714 g_utime (const gchar    *filename,
1715 	 struct utimbuf *utb)
1716 {
1717 #ifdef G_OS_WIN32
1718   wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
1719   int retval;
1720   int save_errno;
1721 
1722   if (wfilename == NULL)
1723     {
1724       errno = EINVAL;
1725       return -1;
1726     }
1727 
1728   retval = _wutime (wfilename, (struct _utimbuf*) utb);
1729   save_errno = errno;
1730 
1731   g_free (wfilename);
1732 
1733   errno = save_errno;
1734   return retval;
1735 #else
1736   return utime (filename, utb);
1737 #endif
1738 }
1739 
1740 /**
1741  * g_close:
1742  * @fd: A file descriptor
1743  * @error: a #GError
1744  *
1745  * This wraps the close() call; in case of error, %errno will be
1746  * preserved, but the error will also be stored as a #GError in @error.
1747  *
1748  * Besides using #GError, there is another major reason to prefer this
1749  * function over the call provided by the system; on Unix, it will
1750  * attempt to correctly handle %EINTR, which has platform-specific
1751  * semantics.
1752  *
1753  * Returns: %TRUE on success, %FALSE if there was an error.
1754  *
1755  * Since: 2.36
1756  */
1757 gboolean
g_close(gint fd,GError ** error)1758 g_close (gint       fd,
1759          GError   **error)
1760 {
1761   int res;
1762   res = close (fd);
1763   /* Just ignore EINTR for now; a retry loop is the wrong thing to do
1764    * on Linux at least.  Anyone who wants to add a conditional check
1765    * for e.g. HP-UX is welcome to do so later...
1766    *
1767    * http://lkml.indiana.edu/hypermail/linux/kernel/0509.1/0877.html
1768    * https://bugzilla.gnome.org/show_bug.cgi?id=682819
1769    * http://utcc.utoronto.ca/~cks/space/blog/unix/CloseEINTR
1770    * https://sites.google.com/site/michaelsafyan/software-engineering/checkforeintrwheninvokingclosethinkagain
1771    */
1772   if (G_UNLIKELY (res == -1 && errno == EINTR))
1773     return TRUE;
1774   else if (res == -1)
1775     {
1776       int errsv = errno;
1777       g_set_error_literal (error, G_FILE_ERROR,
1778                            g_file_error_from_errno (errsv),
1779                            g_strerror (errsv));
1780       errno = errsv;
1781       return FALSE;
1782     }
1783   return TRUE;
1784 }
1785