Coverage Report

Created: 2025-07-18 07:25

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