Coverage Report

Created: 2025-11-11 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/glib/glib/gstdio.c
Line
Count
Source
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
933
g_access (const gchar *filename,
934
    int          mode)
935
0
{
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
0
  return access (filename, mode);
960
0
#endif
961
0
}
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
985
g_chmod (const gchar *filename,
986
   int          mode)
987
0
{
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
0
  return chmod (filename, mode);
1008
0
#endif
1009
0
}
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
1043
g_open (const gchar *filename,
1044
  int          flags,
1045
  int          mode)
1046
0
{
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
0
  int fd;
1067
0
  do
1068
0
    fd = open (filename, flags, mode);
1069
0
  while (G_UNLIKELY (fd == -1 && errno == EINTR));
1070
0
  return fd;
1071
0
#endif
1072
0
}
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
1107
g_creat (const gchar *filename,
1108
   int          mode)
1109
0
{
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
0
  return creat (filename, mode);
1130
0
#endif
1131
0
}
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
1151
g_rename (const gchar *oldfilename,
1152
    const gchar *newfilename)
1153
0
{
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
0
  return rename (oldfilename, newfilename);
1190
0
#endif
1191
0
}
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
1211
g_mkdir (const gchar *filename,
1212
   int          mode)
1213
0
{
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
0
  return mkdir (filename, mode);
1234
0
#endif
1235
0
}
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
1252
g_chdir (const gchar *path)
1253
0
{
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
0
  return chdir (path);
1274
0
#endif
1275
0
}
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
1319
g_stat (const gchar *filename,
1320
  GStatBuf    *buf)
1321
0
{
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
0
  return stat (filename, buf);
1341
0
#endif
1342
0
}
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
1365
g_lstat (const gchar *filename,
1366
   GStatBuf    *buf)
1367
0
{
1368
0
#ifdef HAVE_LSTAT
1369
  /* This can't be Win32, so don't do the widechar dance. */
1370
0
  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
0
}
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
1413
g_unlink (const gchar *filename)
1414
0
{
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
0
  return unlink (filename);
1435
0
#endif
1436
0
}
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
1466
g_remove (const gchar *filename)
1467
0
{
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
0
  return remove (filename);
1490
0
#endif
1491
0
}
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
1510
g_rmdir (const gchar *filename)
1511
0
{
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
0
  return rmdir (filename);
1532
0
#endif
1533
0
}
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 *
1564
g_fopen (const gchar *filename,
1565
   const gchar *mode)
1566
0
{
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
0
  return fopen (filename, mode);
1599
0
#endif
1600
0
}
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 *
1620
g_freopen (const gchar *filename,
1621
     const gchar *mode,
1622
     FILE        *stream)
1623
0
{
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
0
  return freopen (filename, mode, stream);
1656
0
#endif
1657
0
}
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
1678
g_fsync (gint fd)
1679
0
{
1680
#ifdef G_OS_WIN32
1681
  return _commit (fd);
1682
#elif defined(HAVE_FSYNC) || defined(HAVE_FCNTL_F_FULLFSYNC)
1683
  int retval;
1684
0
  do
1685
#ifdef HAVE_FCNTL_F_FULLFSYNC
1686
    retval = fcntl (fd, F_FULLFSYNC, 0);
1687
#else
1688
0
    retval = fsync (fd);
1689
0
#endif
1690
0
  while (G_UNLIKELY (retval < 0 && errno == EINTR));
1691
0
  return retval;
1692
#else
1693
  return 0;
1694
#endif
1695
0
}
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
1714
g_utime (const gchar    *filename,
1715
   struct utimbuf *utb)
1716
0
{
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
0
  return utime (filename, utb);
1737
0
#endif
1738
0
}
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
1758
g_close (gint       fd,
1759
         GError   **error)
1760
0
{
1761
0
  int res;
1762
0
  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
0
  if (G_UNLIKELY (res == -1 && errno == EINTR))
1773
0
    return TRUE;
1774
0
  else if (res == -1)
1775
0
    {
1776
0
      int errsv = errno;
1777
0
      g_set_error_literal (error, G_FILE_ERROR,
1778
0
                           g_file_error_from_errno (errsv),
1779
0
                           g_strerror (errsv));
1780
0
      errno = errsv;
1781
0
      return FALSE;
1782
0
    }
1783
0
  return TRUE;
1784
0
}