GitLab repository storage has been migrated to hashed layout. Please contact Infrastructure team if you notice any issues with repositories or hooks.

gfileutils.c 33.8 KB
Newer Older
Havoc Pennington's avatar
Havoc Pennington committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/* gfileutils.c - File utility functions
 *
 *  Copyright 2000 Red Hat, Inc.
 *
 * GLib is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * GLib is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with GLib; see the file COPYING.LIB.  If not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 *   Boston, MA 02111-1307, USA.
 */

21 22
#include "config.h"

23
#include "galias.h"
Havoc Pennington's avatar
Havoc Pennington committed
24 25 26
#include "glib.h"

#include <sys/stat.h>
27
#ifdef HAVE_UNISTD_H
Havoc Pennington's avatar
Havoc Pennington committed
28
#include <unistd.h>
29
#endif
Havoc Pennington's avatar
Havoc Pennington committed
30
#include <stdio.h>
31
#include <stdlib.h>
32
#include <stdarg.h>
Havoc Pennington's avatar
Havoc Pennington committed
33 34 35 36 37
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
38
#include <stdlib.h>
Havoc Pennington's avatar
Havoc Pennington committed
39

40
#ifdef G_OS_WIN32
41
#include <windows.h>
42 43
#endif /* G_OS_WIN32 */

44
#ifndef S_ISLNK
45
#define S_ISLNK(x) 0
46
#endif
Havoc Pennington's avatar
Havoc Pennington committed
47

48 49 50 51
#ifndef O_BINARY
#define O_BINARY 0
#endif

52
#include "gstdio.h"
Owen Taylor's avatar
Owen Taylor committed
53
#include "glibintl.h"
Havoc Pennington's avatar
Havoc Pennington committed
54 55 56

/**
 * g_file_test:
57
 * @filename: a filename to test in the GLib file name encoding
Havoc Pennington's avatar
Havoc Pennington committed
58 59
 * @test: bitfield of #GFileTest flags
 * 
Matthias Clasen's avatar
Matthias Clasen committed
60 61 62 63 64
 * Returns %TRUE if any of the tests in the bitfield @test are
 * %TRUE. For example, <literal>(G_FILE_TEST_EXISTS | 
 * G_FILE_TEST_IS_DIR)</literal> will return %TRUE if the file exists; 
 * the check whether it's a directory doesn't matter since the existence 
 * test is %TRUE. With the current set of available tests, there's no point
Havoc Pennington's avatar
Havoc Pennington committed
65
 * passing in more than one test at a time.
66
 * 
67
 * Apart from %G_FILE_TEST_IS_SYMLINK all tests follow symbolic links,
68
 * so for a symbolic link to a regular file g_file_test() will return
69
 * %TRUE for both %G_FILE_TEST_IS_SYMLINK and %G_FILE_TEST_IS_REGULAR.
Havoc Pennington's avatar
Havoc Pennington committed
70
 *
Sebastian Wilhelmi's avatar
Sebastian Wilhelmi committed
71
 * Note, that for a dangling symbolic link g_file_test() will return
72 73 74
 * %TRUE for %G_FILE_TEST_IS_SYMLINK and %FALSE for all other flags.
 *
 * You should never use g_file_test() to test whether it is safe
Matthias Clasen's avatar
Matthias Clasen committed
75
 * to perform an operation, because there is always the possibility
76 77 78 79 80 81 82 83
 * of the condition changing before you actually perform the operation.
 * For example, you might think you could use %G_FILE_TEST_IS_SYMLINK
 * to know whether it is is safe to write to a file without being
 * tricked into writing into a different location. It doesn't work!
 *
 * <informalexample><programlisting>
 * /&ast; DON'T DO THIS &ast;/
 *  if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) {
84
 *    fd = g_open (filename, O_WRONLY);
85 86 87 88 89 90 91 92
 *    /&ast; write to fd &ast;/
 *  }
 * </programlisting></informalexample>
 *
 * Another thing to note is that %G_FILE_TEST_EXISTS and
 * %G_FILE_TEST_IS_EXECUTABLE are implemented using the access()
 * system call. This usually doesn't matter, but if your program
 * is setuid or setgid it means that these tests will give you
Matthias Clasen's avatar
Matthias Clasen committed
93
 * the answer for the real user ID and group ID, rather than the
94
 * effective user ID and group ID.
Sebastian Wilhelmi's avatar
Sebastian Wilhelmi committed
95
 *
96 97 98 99 100 101
 * On Windows, there are no symlinks, so testing for
 * %G_FILE_TEST_IS_SYMLINK will always return %FALSE. Testing for
 * %G_FILE_TEST_IS_EXECUTABLE will just check that the file exists and
 * its name indicates that it is executable, checking for well-known
 * extensions and those listed in the %PATHEXT environment variable.
 *
Matthias Clasen's avatar
Matthias Clasen committed
102
 * Return value: whether a test was %TRUE
Havoc Pennington's avatar
Havoc Pennington committed
103 104 105 106 107
 **/
gboolean
g_file_test (const gchar *filename,
             GFileTest    test)
{
108
#ifdef G_OS_WIN32
109 110
  int attributes;

111 112 113 114 115 116 117
  if (G_WIN32_HAVE_WIDECHAR_API ())
    {
      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);

      if (wfilename == NULL)
	return FALSE;

118
      attributes = GetFileAttributesW (wfilename);
119 120 121 122 123

      g_free (wfilename);
    }
  else
    {
124
      gchar *cpfilename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
125

126
      if (cpfilename == NULL)
127 128
	return FALSE;
      
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
      attributes = GetFileAttributesA (cpfilename);
      
      g_free (cpfilename);
    }

  if (attributes == INVALID_FILE_ATTRIBUTES)
    return FALSE;

  if (test & G_FILE_TEST_EXISTS)
    return TRUE;
      
  if (test & G_FILE_TEST_IS_REGULAR)
    return (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0;

  if (test & G_FILE_TEST_IS_DIR)
    return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;

  if (test & G_FILE_TEST_IS_EXECUTABLE)
    {
      const gchar *lastdot = strrchr (filename, '.');
149
      const gchar *pathext = NULL, *p;
150 151 152 153 154 155 156 157 158 159 160 161 162
      int extlen;

      if (lastdot == NULL)
	return FALSE;

      if (stricmp (lastdot, ".exe") == 0 ||
	  stricmp (lastdot, ".cmd") == 0 ||
	  stricmp (lastdot, ".bat") == 0 ||
	  stricmp (lastdot, ".com") == 0)
	return TRUE;

      /* Check if it is one of the types listed in %PATHEXT% */

163
      pathext = g_getenv ("PATHEXT");
164 165 166 167 168 169 170 171 172 173 174
      if (pathext == NULL)
	return FALSE;

      pathext = g_utf8_casefold (pathext, -1);

      lastdot = g_utf8_casefold (lastdot, -1);
      extlen = strlen (lastdot);

      p = pathext;
      while (TRUE)
	{
175
	  const gchar *q = strchr (p, ';');
176 177 178 179
	  if (q == NULL)
	    q = p + strlen (p);
	  if (extlen == q - p &&
	      memcmp (lastdot, p, extlen) == 0)
180
	    {
181
	      g_free ((gchar *) pathext);
182 183
	      g_free ((gchar *) lastdot);
	      return TRUE;
184
	    }
185 186 187 188
	  if (*q)
	    p = q + 1;
	  else
	    break;
189 190
	}

191
      g_free ((gchar *) pathext);
192
      g_free ((gchar *) lastdot);
193 194
      return FALSE;
    }
195 196

  return FALSE;
197
#else
198 199 200 201
  if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0))
    return TRUE;
  
  if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access (filename, X_OK) == 0))
202 203 204 205 206 207 208 209 210 211 212
    {
      if (getuid () != 0)
	return TRUE;

      /* For root, on some POSIX systems, access (filename, X_OK)
       * will succeed even if no executable bits are set on the
       * file. We fall through to a stat test to avoid that.
       */
    }
  else
    test &= ~G_FILE_TEST_IS_EXECUTABLE;
213 214

  if (test & G_FILE_TEST_IS_SYMLINK)
Havoc Pennington's avatar
Havoc Pennington committed
215 216 217
    {
      struct stat s;

218
      if ((lstat (filename, &s) == 0) && S_ISLNK (s.st_mode))
Havoc Pennington's avatar
Havoc Pennington committed
219 220
        return TRUE;
    }
221
  
222 223 224
  if (test & (G_FILE_TEST_IS_REGULAR |
	      G_FILE_TEST_IS_DIR |
	      G_FILE_TEST_IS_EXECUTABLE))
225 226 227 228 229 230 231 232 233 234
    {
      struct stat s;
      
      if (stat (filename, &s) == 0)
	{
	  if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
	    return TRUE;
	  
	  if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
	    return TRUE;
235 236 237 238 239 240 241 242

	  /* The extra test for root when access (file, X_OK) succeeds.
	   */
	  if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
	      ((s.st_mode & S_IXOTH) ||
	       (s.st_mode & S_IXUSR) ||
	       (s.st_mode & S_IXGRP)))
	    return TRUE;
243 244 245 246
	}
    }

  return FALSE;
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
#endif
}

#ifdef G_OS_WIN32

#undef g_file_test

/* Binary compatibility version. Not for newly compiled code. */

gboolean
g_file_test (const gchar *filename,
             GFileTest    test)
{
  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, NULL);
  gboolean retval;

  if (utf8_filename == NULL)
    return FALSE;

  retval = g_file_test_utf8 (utf8_filename, test);

  g_free (utf8_filename);

  return retval;
Havoc Pennington's avatar
Havoc Pennington committed
271 272
}

273 274
#endif

Havoc Pennington's avatar
Havoc Pennington committed
275 276 277 278 279 280 281 282 283 284
GQuark
g_file_error_quark (void)
{
  static GQuark q = 0;
  if (q == 0)
    q = g_quark_from_static_string ("g-file-error-quark");

  return q;
}

Havoc Pennington's avatar
docs  
Havoc Pennington committed
285 286 287 288
/**
 * g_file_error_from_errno:
 * @err_no: an "errno" value
 * 
Matthias Clasen's avatar
Matthias Clasen committed
289 290 291
 * Gets a #GFileError constant based on the passed-in @errno.
 * For example, if you pass in %EEXIST this function returns
 * #G_FILE_ERROR_EXIST. Unlike @errno values, you can portably
Havoc Pennington's avatar
docs  
Havoc Pennington committed
292 293 294 295 296 297
 * assume that all #GFileError values will exist.
 *
 * Normally a #GFileError value goes into a #GError returned
 * from a function that manipulates files. So you would use
 * g_file_error_from_errno() when constructing a #GError.
 * 
Matthias Clasen's avatar
Matthias Clasen committed
298
 * Return value: #GFileError corresponding to the given @errno
Havoc Pennington's avatar
docs  
Havoc Pennington committed
299
 **/
Havoc Pennington's avatar
Havoc Pennington committed
300
GFileError
Havoc Pennington's avatar
docs  
Havoc Pennington committed
301
g_file_error_from_errno (gint err_no)
Havoc Pennington's avatar
Havoc Pennington committed
302
{
Havoc Pennington's avatar
docs  
Havoc Pennington committed
303
  switch (err_no)
Havoc Pennington's avatar
Havoc Pennington committed
304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
    {
#ifdef EEXIST
    case EEXIST:
      return G_FILE_ERROR_EXIST;
      break;
#endif

#ifdef EISDIR
    case EISDIR:
      return G_FILE_ERROR_ISDIR;
      break;
#endif

#ifdef EACCES
    case EACCES:
      return G_FILE_ERROR_ACCES;
      break;
#endif

#ifdef ENAMETOOLONG
    case ENAMETOOLONG:
      return G_FILE_ERROR_NAMETOOLONG;
      break;
#endif

#ifdef ENOENT
    case ENOENT:
      return G_FILE_ERROR_NOENT;
      break;
#endif

#ifdef ENOTDIR
    case ENOTDIR:
      return G_FILE_ERROR_NOTDIR;
      break;
#endif

#ifdef ENXIO
    case ENXIO:
      return G_FILE_ERROR_NXIO;
      break;
#endif

#ifdef ENODEV
    case ENODEV:
      return G_FILE_ERROR_NODEV;
      break;
#endif

#ifdef EROFS
    case EROFS:
      return G_FILE_ERROR_ROFS;
      break;
#endif

#ifdef ETXTBSY
    case ETXTBSY:
      return G_FILE_ERROR_TXTBSY;
      break;
#endif

#ifdef EFAULT
    case EFAULT:
      return G_FILE_ERROR_FAULT;
      break;
#endif

#ifdef ELOOP
    case ELOOP:
      return G_FILE_ERROR_LOOP;
      break;
#endif

#ifdef ENOSPC
    case ENOSPC:
      return G_FILE_ERROR_NOSPC;
      break;
#endif

#ifdef ENOMEM
    case ENOMEM:
      return G_FILE_ERROR_NOMEM;
      break;
#endif

#ifdef EMFILE
    case EMFILE:
      return G_FILE_ERROR_MFILE;
      break;
#endif

#ifdef ENFILE
    case ENFILE:
      return G_FILE_ERROR_NFILE;
      break;
#endif

#ifdef EBADF
    case EBADF:
      return G_FILE_ERROR_BADF;
      break;
#endif

#ifdef EINVAL
    case EINVAL:
      return G_FILE_ERROR_INVAL;
      break;
#endif

#ifdef EPIPE
    case EPIPE:
      return G_FILE_ERROR_PIPE;
      break;
#endif

#ifdef EAGAIN
    case EAGAIN:
      return G_FILE_ERROR_AGAIN;
      break;
#endif

#ifdef EINTR
    case EINTR:
      return G_FILE_ERROR_INTR;
      break;
#endif

#ifdef EIO
    case EIO:
      return G_FILE_ERROR_IO;
      break;
#endif

#ifdef EPERM
    case EPERM:
      return G_FILE_ERROR_PERM;
      break;
#endif
Matthias Clasen's avatar
Matthias Clasen committed
442 443 444 445 446 447 448

#ifdef ENOSYS
    case ENOSYS:
      return G_FILE_ERROR_NOSYS;
      break;
#endif

Havoc Pennington's avatar
Havoc Pennington committed
449 450 451 452 453 454 455
    default:
      return G_FILE_ERROR_FAILED;
      break;
    }
}

static gboolean
456
get_contents_stdio (const gchar *display_filename,
Havoc Pennington's avatar
Havoc Pennington committed
457 458
                    FILE        *f,
                    gchar      **contents,
459
                    gsize       *length, 
Havoc Pennington's avatar
Havoc Pennington committed
460 461 462 463
                    GError     **error)
{
  gchar buf[2048];
  size_t bytes;
464 465 466 467
  char *str;
  size_t total_bytes;
  size_t total_allocated;
  
Havoc Pennington's avatar
Havoc Pennington committed
468
  g_assert (f != NULL);
469 470

#define STARTING_ALLOC 64
Havoc Pennington's avatar
Havoc Pennington committed
471
  
472 473 474
  total_bytes = 0;
  total_allocated = STARTING_ALLOC;
  str = g_malloc (STARTING_ALLOC);
Havoc Pennington's avatar
Havoc Pennington committed
475 476 477 478
  
  while (!feof (f))
    {
      bytes = fread (buf, 1, 2048, f);
479 480 481 482 483 484 485 486 487 488 489 490

      while ((total_bytes + bytes + 1) > total_allocated)
        {
          total_allocated *= 2;
          str = g_try_realloc (str, total_allocated);

          if (str == NULL)
            {
              g_set_error (error,
                           G_FILE_ERROR,
                           G_FILE_ERROR_NOMEM,
                           _("Could not allocate %lu bytes to read file \"%s\""),
491
                           (gulong) total_allocated, 
492
			   display_filename);
493

494 495 496
              goto error;
            }
        }
Havoc Pennington's avatar
Havoc Pennington committed
497 498 499 500 501 502 503
      
      if (ferror (f))
        {
          g_set_error (error,
                       G_FILE_ERROR,
                       g_file_error_from_errno (errno),
                       _("Error reading file '%s': %s"),
504
                       display_filename,
505
		       g_strerror (errno));
Havoc Pennington's avatar
Havoc Pennington committed
506

507
          goto error;
Havoc Pennington's avatar
Havoc Pennington committed
508 509
        }

510 511
      memcpy (str + total_bytes, buf, bytes);
      total_bytes += bytes;
Havoc Pennington's avatar
Havoc Pennington committed
512 513 514 515
    }

  fclose (f);

516 517
  str[total_bytes] = '\0';
  
Havoc Pennington's avatar
Havoc Pennington committed
518
  if (length)
519
    *length = total_bytes;
Havoc Pennington's avatar
Havoc Pennington committed
520
  
521 522 523 524 525
  *contents = str;
  
  return TRUE;

 error:
Havoc Pennington's avatar
Havoc Pennington committed
526

527 528 529 530
  g_free (str);
  fclose (f);
  
  return FALSE;  
Havoc Pennington's avatar
Havoc Pennington committed
531 532
}

533 534
#ifndef G_OS_WIN32

Havoc Pennington's avatar
Havoc Pennington committed
535
static gboolean
536
get_contents_regfile (const gchar *display_filename,
Havoc Pennington's avatar
Havoc Pennington committed
537 538 539
                      struct stat *stat_buf,
                      gint         fd,
                      gchar      **contents,
540
                      gsize       *length,
Havoc Pennington's avatar
Havoc Pennington committed
541 542 543 544 545
                      GError     **error)
{
  gchar *buf;
  size_t bytes_read;
  size_t size;
546 547
  size_t alloc_size;
  
Havoc Pennington's avatar
Havoc Pennington committed
548 549
  size = stat_buf->st_size;

550 551 552 553 554 555 556 557 558
  alloc_size = size + 1;
  buf = g_try_malloc (alloc_size);

  if (buf == NULL)
    {
      g_set_error (error,
                   G_FILE_ERROR,
                   G_FILE_ERROR_NOMEM,
                   _("Could not allocate %lu bytes to read file \"%s\""),
559
                   (gulong) alloc_size, 
560
		   display_filename);
561

562
      goto error;
563 564
    }
  
Havoc Pennington's avatar
Havoc Pennington committed
565 566 567
  bytes_read = 0;
  while (bytes_read < size)
    {
568
      gssize rc;
Havoc Pennington's avatar
Havoc Pennington committed
569 570 571 572 573 574 575
          
      rc = read (fd, buf + bytes_read, size - bytes_read);

      if (rc < 0)
        {
          if (errno != EINTR) 
            {
576
              g_free (buf);
Havoc Pennington's avatar
Havoc Pennington committed
577 578 579 580
              g_set_error (error,
                           G_FILE_ERROR,
                           g_file_error_from_errno (errno),
                           _("Failed to read from file '%s': %s"),
581
                           display_filename, 
582
			   g_strerror (errno));
Havoc Pennington's avatar
Havoc Pennington committed
583

584
	      goto error;
Havoc Pennington's avatar
Havoc Pennington committed
585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
            }
        }
      else if (rc == 0)
        break;
      else
        bytes_read += rc;
    }
      
  buf[bytes_read] = '\0';

  if (length)
    *length = bytes_read;
  
  *contents = buf;

600 601
  close (fd);

Havoc Pennington's avatar
Havoc Pennington committed
602
  return TRUE;
603 604 605 606 607 608

 error:

  close (fd);
  
  return FALSE;
Havoc Pennington's avatar
Havoc Pennington committed
609 610 611 612 613
}

static gboolean
get_contents_posix (const gchar *filename,
                    gchar      **contents,
614
                    gsize       *length,
Havoc Pennington's avatar
Havoc Pennington committed
615 616 617 618
                    GError     **error)
{
  struct stat stat_buf;
  gint fd;
619
  gchar *display_filename = g_filename_display_name (filename);
620

621 622
  /* O_BINARY useful on Cygwin */
  fd = open (filename, O_RDONLY|O_BINARY);
Havoc Pennington's avatar
Havoc Pennington committed
623 624 625 626 627 628 629

  if (fd < 0)
    {
      g_set_error (error,
                   G_FILE_ERROR,
                   g_file_error_from_errno (errno),
                   _("Failed to open file '%s': %s"),
630
                   display_filename, 
631
		   g_strerror (errno));
632
      g_free (display_filename);
Havoc Pennington's avatar
Havoc Pennington committed
633 634 635 636 637 638 639

      return FALSE;
    }

  /* I don't think this will ever fail, aside from ENOMEM, but. */
  if (fstat (fd, &stat_buf) < 0)
    {
640
      close (fd);
Havoc Pennington's avatar
Havoc Pennington committed
641 642 643 644
      g_set_error (error,
                   G_FILE_ERROR,
                   g_file_error_from_errno (errno),
                   _("Failed to get attributes of file '%s': fstat() failed: %s"),
645
                   display_filename, 
646
		   g_strerror (errno));
647
      g_free (display_filename);
Havoc Pennington's avatar
Havoc Pennington committed
648 649 650 651 652 653

      return FALSE;
    }

  if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
    {
654
      gboolean retval = get_contents_regfile (display_filename,
655 656 657 658 659
					      &stat_buf,
					      fd,
					      contents,
					      length,
					      error);
660
      g_free (display_filename);
661 662

      return retval;
Havoc Pennington's avatar
Havoc Pennington committed
663 664 665 666
    }
  else
    {
      FILE *f;
667
      gboolean retval;
Havoc Pennington's avatar
Havoc Pennington committed
668 669 670 671 672 673 674 675 676

      f = fdopen (fd, "r");
      
      if (f == NULL)
        {
          g_set_error (error,
                       G_FILE_ERROR,
                       g_file_error_from_errno (errno),
                       _("Failed to open file '%s': fdopen() failed: %s"),
677
                       display_filename, 
678
		       g_strerror (errno));
679
          g_free (display_filename);
680

Havoc Pennington's avatar
Havoc Pennington committed
681 682 683
          return FALSE;
        }
  
684 685
      retval = get_contents_stdio (display_filename, f, contents, length, error);
      g_free (display_filename);
686 687

      return retval;
Havoc Pennington's avatar
Havoc Pennington committed
688 689 690
    }
}

691 692
#else  /* G_OS_WIN32 */

Havoc Pennington's avatar
Havoc Pennington committed
693 694
static gboolean
get_contents_win32 (const gchar *filename,
695 696 697
		    gchar      **contents,
		    gsize       *length,
		    GError     **error)
Havoc Pennington's avatar
Havoc Pennington committed
698 699
{
  FILE *f;
700 701
  gboolean retval;
  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
702
  gchar *display_filename = g_filename_display_name (filename);
703 704 705
  
  f = _wfopen (wfilename, L"rb");
  g_free (wfilename);
Havoc Pennington's avatar
Havoc Pennington committed
706 707 708 709 710 711 712

  if (f == NULL)
    {
      g_set_error (error,
                   G_FILE_ERROR,
                   g_file_error_from_errno (errno),
                   _("Failed to open file '%s': %s"),
713
                   display_filename,
714
		   g_strerror (errno));
715
      g_free (display_filename);
716

Havoc Pennington's avatar
Havoc Pennington committed
717 718 719
      return FALSE;
    }
  
720 721
  retval = get_contents_stdio (display_filename, f, contents, length, error);
  g_free (display_filename);
722 723

  return retval;
Havoc Pennington's avatar
Havoc Pennington committed
724
}
725

Havoc Pennington's avatar
Havoc Pennington committed
726 727 728 729
#endif

/**
 * g_file_get_contents:
730
 * @filename: name of a file to read contents from, in the GLib file name encoding
Havoc Pennington's avatar
Havoc Pennington committed
731
 * @contents: location to store an allocated string
732 733
 * @length: location to store length in bytes of the contents, or %NULL
 * @error: return location for a #GError, or %NULL
Havoc Pennington's avatar
Havoc Pennington committed
734 735
 * 
 * Reads an entire file into allocated memory, with good error
736
 * checking. 
Havoc Pennington's avatar
Havoc Pennington committed
737
 *
738 739 740 741 742 743 744 745 746
 * If the call was successful, it returns %TRUE and sets @contents to the file 
 * contents and @length to the length of the file contents in bytes. The string 
 * stored in @contents will be nul-terminated, so for text files you can pass 
 * %NULL for the @length argument. If the call was not successful, it returns 
 * %FALSE and sets @error. The error domain is #G_FILE_ERROR. Possible error  
 * codes are those in the #GFileError enumeration. In the error case, 
 * @contents is set to %NULL and @length is set to zero.
 *
 * Return value: %TRUE on success, %FALSE if an error occurred
Havoc Pennington's avatar
Havoc Pennington committed
747 748 749 750
 **/
gboolean
g_file_get_contents (const gchar *filename,
                     gchar      **contents,
751
                     gsize       *length,
Havoc Pennington's avatar
Havoc Pennington committed
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
                     GError     **error)
{  
  g_return_val_if_fail (filename != NULL, FALSE);
  g_return_val_if_fail (contents != NULL, FALSE);

  *contents = NULL;
  if (length)
    *length = 0;

#ifdef G_OS_WIN32
  return get_contents_win32 (filename, contents, length, error);
#else
  return get_contents_posix (filename, contents, length, error);
#endif
}
767

768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794
#ifdef G_OS_WIN32

#undef g_file_get_contents

/* Binary compatibility version. Not for newly compiled code. */

gboolean
g_file_get_contents (const gchar *filename,
                     gchar      **contents,
                     gsize       *length,
                     GError     **error)
{
  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
  gboolean retval;

  if (utf8_filename == NULL)
    return FALSE;

  retval = g_file_get_contents (utf8_filename, contents, length, error);

  g_free (utf8_filename);

  return retval;
}

#endif

Havoc Pennington's avatar
Added  
Havoc Pennington committed
795 796 797 798
/*
 * mkstemp() implementation is from the GNU C library.
 * Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc.
 */
799 800
/**
 * g_mkstemp:
Havoc Pennington's avatar
Added  
Havoc Pennington committed
801
 * @tmpl: template filename
802
 *
803
 * Opens a temporary file. See the mkstemp() documentation
Matthias Clasen's avatar
Matthias Clasen committed
804
 * on most UNIX-like systems. This is a portability wrapper, which simply calls 
805
 * mkstemp() on systems that have it, and implements 
Matthias Clasen's avatar
Matthias Clasen committed
806
 * it in GLib otherwise.
807
 *
Matthias Clasen's avatar
Matthias Clasen committed
808
 * The parameter is a string that should match the rules for
809
 * mkstemp(), i.e. end in "XXXXXX". The X string will 
Matthias Clasen's avatar
Matthias Clasen committed
810
 * be modified to form the name of a file that didn't exist.
811 812
 * The string should be in the GLib file name encoding. Most importantly, 
 * on Windows it should be in UTF-8.
813
 *
814
 * Return value: A file handle (as from open()) to the file
815 816
 * opened for reading and writing. The file is opened in binary mode
 * on platforms where there is a difference. The file handle should be
817
 * closed with close(). In case of errors, -1 is returned.
818
 */
819 820
gint
g_mkstemp (gchar *tmpl)
821 822 823 824 825 826 827 828
{
#ifdef HAVE_MKSTEMP
  return mkstemp (tmpl);
#else
  int len;
  char *XXXXXX;
  int count, fd;
  static const char letters[] =
829 830
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  static const int NLETTERS = sizeof (letters) - 1;
831 832
  glong value;
  GTimeVal tv;
833
  static int counter = 0;
834 835 836 837 838 839 840 841 842 843

  len = strlen (tmpl);
  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
    return -1;

  /* This is where the Xs start.  */
  XXXXXX = &tmpl[len - 6];

  /* Get some more or less random data.  */
  g_get_current_time (&tv);
844
  value = (tv.tv_usec ^ tv.tv_sec) + counter++;
845 846 847 848 849 850

  for (count = 0; count < 100; value += 7777, ++count)
    {
      glong v = value;

      /* Fill in the random bits.  */
851 852 853 854 855 856 857 858 859 860 861
      XXXXXX[0] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[1] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[2] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[3] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[4] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[5] = letters[v % NLETTERS];
862

863 864
      /* tmpl is in UTF-8 on Windows, thus use g_open() */
      fd = g_open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
865 866 867 868 869 870 871 872 873 874 875 876 877 878

      if (fd >= 0)
	return fd;
      else if (errno != EEXIST)
	/* Any other error will apply also to other names we might
	 *  try, and there are 2^32 or so of them, so give up now.
	 */
	return -1;
    }

  /* We got out of the loop because we ran out of combinations to try.  */
  return -1;
#endif
}
879

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
#ifdef G_OS_WIN32

#undef g_mkstemp

/* Binary compatibility version. Not for newly compiled code. */

gint
g_mkstemp (gchar *tmpl)
{
  int len;
  char *XXXXXX;
  int count, fd;
  static const char letters[] =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  static const int NLETTERS = sizeof (letters) - 1;
  glong value;
  GTimeVal tv;
  static int counter = 0;

  len = strlen (tmpl);
  if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX"))
    return -1;

  /* This is where the Xs start.  */
  XXXXXX = &tmpl[len - 6];

  /* Get some more or less random data.  */
  g_get_current_time (&tv);
  value = (tv.tv_usec ^ tv.tv_sec) + counter++;

  for (count = 0; count < 100; value += 7777, ++count)
    {
      glong v = value;

      /* Fill in the random bits.  */
      XXXXXX[0] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[1] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[2] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[3] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[4] = letters[v % NLETTERS];
      v /= NLETTERS;
      XXXXXX[5] = letters[v % NLETTERS];

      /* This is the backward compatibility system codepage version,
       * thus use normal open().
       */
      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);

      if (fd >= 0)
	return fd;
      else if (errno != EEXIST)
	/* Any other error will apply also to other names we might
	 *  try, and there are 2^32 or so of them, so give up now.
	 */
	return -1;
    }

  /* We got out of the loop because we ran out of combinations to try.  */
  return -1;
}

#endif

947 948
/**
 * g_file_open_tmp:
Matthias Clasen's avatar
Matthias Clasen committed
949
 * @tmpl: Template for file name, as in g_mkstemp(), basename only
950 951 952 953 954 955
 * @name_used: location to store actual name used
 * @error: return location for a #GError
 *
 * Opens a file for writing in the preferred directory for temporary
 * files (as returned by g_get_tmp_dir()). 
 *
956 957 958 959 960
 * @tmpl should be a string in the GLib file name encoding ending with
 * six 'X' characters, as the parameter to g_mkstemp() (or mkstemp()).
 * However, unlike these functions, the template should only be a
 * basename, no directory components are allowed. If template is
 * %NULL, a default template is used.
961
 *
962
 * Note that in contrast to g_mkstemp() (and mkstemp()) 
Matthias Clasen's avatar
Matthias Clasen committed
963
 * @tmpl is not modified, and might thus be a read-only literal string.
964
 *
Matthias Clasen's avatar
Matthias Clasen committed
965 966
 * The actual name used is returned in @name_used if non-%NULL. This
 * string should be freed with g_free() when not needed any longer.
967
 * The returned name is in the GLib file name encoding.
968
 *
969
 * Return value: A file handle (as from open()) to 
Matthias Clasen's avatar
Matthias Clasen committed
970 971
 * the file opened for reading and writing. The file is opened in binary 
 * mode on platforms where there is a difference. The file handle should be
972
 * closed with close(). In case of errors, -1 is returned 
Matthias Clasen's avatar
Matthias Clasen committed
973
 * and @error will be set.
974
 **/
975 976 977 978
gint
g_file_open_tmp (const gchar *tmpl,
		 gchar      **name_used,
		 GError     **error)
979 980
{
  int retval;
Havoc Pennington's avatar
Havoc Pennington committed
981
  const char *tmpdir;
982 983
  char *sep;
  char *fulltemplate;
Tor Lillqvist's avatar
Tor Lillqvist committed
984
  const char *slash;
985

986 987
  if (tmpl == NULL)
    tmpl = ".XXXXXX";
988

Tor Lillqvist's avatar
Tor Lillqvist committed
989
  if ((slash = strchr (tmpl, G_DIR_SEPARATOR)) != NULL
990
#ifdef G_OS_WIN32
Tor Lillqvist's avatar
Tor Lillqvist committed
991
      || (strchr (tmpl, '/') != NULL && (slash = "/"))
992
#endif
Tor Lillqvist's avatar
Tor Lillqvist committed
993
      )
994
    {
995
      gchar *display_tmpl = g_filename_display_name (tmpl);
Tor Lillqvist's avatar
Tor Lillqvist committed
996 997 998 999
      char c[2];
      c[0] = *slash;
      c[1] = '\0';

1000 1001 1002
      g_set_error (error,
		   G_FILE_ERROR,
		   G_FILE_ERROR_FAILED,
1003
		   _("Template '%s' invalid, should not contain a '%s'"),
1004 1005
		   display_tmpl, c);
      g_free (display_tmpl);
1006 1007 1008 1009

      return -1;
    }
  
1010 1011
  if (strlen (tmpl) < 6 ||
      strcmp (tmpl + strlen (tmpl) - 6, "XXXXXX") != 0)
1012
    {
1013
      gchar *display_tmpl = g_filename_display_name (tmpl);
1014 1015 1016
      g_set_error (error,
		   G_FILE_ERROR,
		   G_FILE_ERROR_FAILED,
Kjartan Maraas's avatar
Kjartan Maraas committed
1017
		   _("Template '%s' doesn't end with XXXXXX"),
1018 1019
		   display_tmpl);
      g_free (display_tmpl);
1020 1021 1022 1023 1024
      return -1;
    }

  tmpdir = g_get_tmp_dir ();

Tor Lillqvist's avatar
Tor Lillqvist committed
1025
  if (G_IS_DIR_SEPARATOR (tmpdir [strlen (tmpdir) - 1]))
1026 1027 1028 1029
    sep = "";
  else
    sep = G_DIR_SEPARATOR_S;

1030
  fulltemplate = g_strconcat (tmpdir, sep, tmpl, NULL);
1031 1032 1033 1034 1035

  retval = g_mkstemp (fulltemplate);

  if (retval == -1)
    {
1036
      gchar *display_fulltemplate = g_filename_display_name (fulltemplate);
1037 1038 1039 1040
      g_set_error (error,
		   G_FILE_ERROR,
		   g_file_error_from_errno (errno),
		   _("Failed to create file '%s': %s"),
1041 1042
		   display_fulltemplate, g_strerror (errno));
      g_free (display_fulltemplate);
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
      g_free (fulltemplate);
      return -1;
    }

  if (name_used)
    *name_used = fulltemplate;
  else
    g_free (fulltemplate);

  return retval;
}
1054

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087
#ifdef G_OS_WIN32

#undef g_file_open_tmp

/* Binary compatibility version. Not for newly compiled code. */

gint
g_file_open_tmp (const gchar *tmpl,
		 gchar      **name_used,
		 GError     **error)
{
  gchar *utf8_tmpl = g_locale_to_utf8 (tmpl, -1, NULL, NULL, error);
  gchar *utf8_name_used;
  gint retval;

  if (utf8_tmpl == NULL)
    return -1;

  retval = g_file_open_tmp_utf8 (utf8_tmpl, &utf8_name_used, error);
  
  if (retval == -1)
    return -1;

  if (name_used)
    *name_used = g_locale_from_utf8 (utf8_name_used, -1, NULL, NULL, NULL);

  g_free (utf8_name_used);

  return retval;
}

#endif

1088 1089 1090 1091 1092 1093 1094 1095
static gchar *
g_build_pathv (const gchar *separator,
	       const gchar *first_element,
	       va_list      args)
{
  GString *result;
  gint separator_len = strlen (separator);
  gboolean is_first = TRUE;
1096 1097
  gboolean have_leading = FALSE;
  const gchar *single_element = NULL;
1098
  const gchar *next_element;
1099
  const gchar *last_trailing = NULL;
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118

  result = g_string_new (NULL);

  next_element = first_element;

  while (TRUE)
    {
      const gchar *element;
      const gchar *start;
      const gchar *end;

      if (next_element)
	{
	  element = next_element;
	  next_element = va_arg (args, gchar *);
	}
      else
	break;

1119 1120 1121
      /* Ignore empty elements */
      if (!*element)
	continue;
1122
      
1123 1124 1125
      start = element;

      if (separator_len)
1126 1127 1128 1129
	{
	  while (start &&
		 strncmp (start, separator, separator_len) == 0)
	    start += separator_len;
1130
      	}
1131 1132 1133

      end = start + strlen (start);
      
1134
      if (separator_len)
1135
	{
1136
	  while (end >= start + separator_len &&
1137 1138
		 strncmp (end - separator_len, separator, separator_len) == 0)
	    end -= separator_len;
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
	  
	  last_trailing = end;
	  while (last_trailing >= element + separator_len &&
		 strncmp (last_trailing - separator_len, separator, separator_len) == 0)
	    last_trailing -= separator_len;

	  if (!have_leading)
	    {
	      /* If the leading and trailing separator strings are in the
	       * same element and overlap, the result is exactly that element
	       */
	      if (last_trailing <= start)
		single_element = element;
		  
	      g_string_append_len (result, element, start - element);
	      have_leading = TRUE;
	    }
	  else
	    single_element = NULL;
1158 1159
	}

1160 1161
      if (end == start)
	continue;
1162

1163 1164 1165 1166 1167
      if (!is_first)
	g_string_append (result, separator);
      
      g_string_append_len (result, start, end - start);
      is_first = FALSE;
1168
    }
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178

  if (single_element)
    {
      g_string_free (result, TRUE);
      return g_strdup (single_element);
    }
  else
    {
      if (last_trailing)
	g_string_append (result, last_trailing);
1179
  
1180 1181
      return g_string_free (result, FALSE);
    }
1182 1183 1184 1185 1186 1187
}

/**
 * g_build_path:
 * @separator: a string used to separator the elements of the path.
 * @first_element: the first element in the path
1188
 * @Varargs: remaining elements in path, terminated by %NULL
1189
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1190
 * Creates a path from a series of elements using @separator as the
1191 1192 1193 1194
 * separator between elements. At the boundary between two elements,
 * any trailing occurrences of separator in the first element, or
 * leading occurrences of separator in the second element are removed
 * and exactly one copy of the separator is inserted.
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
 *
 * Empty elements are ignored.
 *
 * The number of leading copies of the separator on the result is
 * the same as the number of leading copies of the separator on
 * the first non-empty element.
 *
 * The number of trailing copies of the separator on the result is
 * the same as the number of trailing copies of the separator on
 * the last non-empty element. (Determination of the number of
 * trailing copies is done without stripping leading copies, so
 * if the separator is <literal>ABA</literal>, <literal>ABABA</literal>
 * has 1 trailing copy.)
 *
 * However, if there is only a single non-empty element, and there
 * are no characters in that element not part of the leading or
 * trailing separators, then the result is exactly the original value
 * of that element.
 *
 * Other than for determination of the number of leading and trailing
 * copies of the separator, elements consisting only of copies
 * of the separator are ignored.
1217
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1218
 * Return value: a newly-allocated string that must be freed with g_free().
1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
 **/
gchar *
g_build_path (const gchar *separator,
	      const gchar *first_element,
	      ...)
{
  gchar *str;
  va_list args;

  g_return_val_if_fail (separator != NULL, NULL);

  va_start (args, first_element);
  str = g_build_pathv (separator, first_element, args);
  va_end (args);

  return str;
}

/**
 * g_build_filename:
 * @first_element: the first element in the path
1240
 * @Varargs: remaining elements in path, terminated by %NULL
1241
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1242
 * Creates a filename from a series of elements using the correct
Tor Lillqvist's avatar
Tor Lillqvist committed
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
 * separator for filenames.
 *
 * On Unix, this function behaves identically to <literal>g_build_path
 * (G_DIR_SEPARATOR_S, first_element, ....)</literal>.
 *
 * On Windows, it takes into account that either the backslash
 * (<literal>\</literal> or slash (<literal>/</literal>) can be used
 * as separator in filenames, but otherwise behaves as on Unix. When
 * file pathname separators need to be inserted, the one that last
 * previously occurred in the parameters (reading from left to right)
 * is used.
1254 1255 1256 1257 1258
 *
 * No attempt is made to force the resulting filename to be an absolute
 * path. If the first element is a relative path, the result will
 * be a relative path. 
 * 
Matthias Clasen's avatar
Matthias Clasen committed
1259
 * Return value: a newly-allocated string that must be freed with g_free().
1260 1261 1262 1263 1264
 **/
gchar *
g_build_filename (const gchar *first_element, 
		  ...)
{
Tor Lillqvist's avatar
Tor Lillqvist committed
1265
#ifndef G_OS_WIN32
1266 1267 1268 1269 1270 1271 1272 1273
  gchar *str;
  va_list args;

  va_start (args, first_element);
  str = g_build_pathv (G_DIR_SEPARATOR_S, first_element, args);
  va_end (args);

  return str;
Tor Lillqvist's avatar
Tor Lillqvist committed
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
#else
  /* Code copied from g_build_pathv(), and modifed to use two
   * alternative single-character separators.
   */
  va_list args;
  GString *result;
  gboolean is_first = TRUE;
  gboolean have_leading = FALSE;
  const gchar *single_element = NULL;
  const gchar *next_element;
  const gchar *last_trailing = NULL;
  gchar current_separator = '\\';

  va_start (args, first_element);

  result = g_string_new (NULL);

  next_element = first_element;

  while (TRUE)
    {
      const gchar *element;
      const gchar *start;
      const gchar *end;

      if (next_element)
	{
	  element = next_element;
	  next_element = va_arg (args, gchar *);
	}
      else
	break;

      /* Ignore empty elements */
      if (!*element)
	continue;
      
      start = element;

      if (TRUE)
	{
	  while (start &&
		 (*start == '\\' || *start == '/'))
	    {
	      current_separator = *start;
	      start++;
	    }
	}

      end = start + strlen (start);
      
      if (TRUE)
	{
	  while (end >= start + 1 &&
		 (end[-1] == '\\' || end[-1] == '/'))
	    {
	      current_separator = end[-1];
	      end--;
	    }
	  
	  last_trailing = end;
	  while (last_trailing >= element + 1 &&
		 (last_trailing[-1] == '\\' || last_trailing[-1] == '/'))
	    last_trailing--;

	  if (!have_leading)
	    {
	      /* If the leading and trailing separator strings are in the
	       * same element and overlap, the result is exactly that element
	       */
	      if (last_trailing <= start)
		single_element = element;
		  
	      g_string_append_len (result, element, start - element);
	      have_leading = TRUE;
	    }
	  else
	    single_element = NULL;
	}

      if (end == start)
	continue;

      if (!is_first)
	g_string_append_len (result, &current_separator, 1);
      
      g_string_append_len (result, start, end - start);
      is_first = FALSE;
    }

  va_end (args);

  if (single_element)
    {
      g_string_free (result, TRUE);
      return g_strdup (single_element);
    }
  else
    {
      if (last_trailing)
	g_string_append (result, last_trailing);
  
      return g_string_free (result, FALSE);
    }
#endif
1379
}
1380 1381

/**
1382
 * g_file_read_link:
1383 1384 1385
 * @filename: the symbolic link
 * @error: return location for a #GError
 *
1386 1387 1388
 * Reads the contents of the symbolic link @filename like the POSIX
 * readlink() function.  The returned string is in the encoding used
 * for filenames. Use g_filename_to_utf8() to convert it to UTF-8.
1389 1390 1391 1392 1393 1394 1395
 *
 * Returns: A newly allocated string with the contents of the symbolic link, 
 *          or %NULL if an error occurred.
 *
 * Since: 2.4
 */
gchar *
1396 1397
g_file_read_link (const gchar *filename,
	          GError     **error)
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
{
#ifdef HAVE_READLINK
  gchar *buffer;
  guint size;
  gint read_size;    
  
  size = 256; 
  buffer = g_malloc (size);
  
  while (TRUE) 
    {
      read_size = readlink (filename, buffer, size);
      if (read_size < 0) {
1411
	gchar *display_filename = g_filename_display_name (filename);
1412
	g_free (buffer);
1413 1414 1415 1416
	g_set_error (error,
		     G_FILE_ERROR,
		     g_file_error_from_errno (errno),
		     _("Failed to read the symbolic link '%s': %s"),
1417
		     display_filename, 
1418
		     g_strerror (errno));
1419
	g_free (display_filename);
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441
	
	return NULL;
      }
    
      if (read_size < size) 
	{
	  buffer[read_size] = 0;
	  return buffer;
	}
      
      size *= 2;
      buffer = g_realloc (buffer, size);
    }
#else
  g_set_error (error,
	       G_FILE_ERROR,
	       G_FILE_ERROR_INVAL,
	       _("Symbolic links not supported"));
	
  return NULL;
#endif
}