Index: glib/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/glib/Makefile.am,v
retrieving revision 1.114
diff -u -2 -r1.114 Makefile.am
--- glib/Makefile.am	2 Aug 2004 21:40:40 -0000	1.114
+++ glib/Makefile.am	21 Aug 2004 21:05:56 -0000
@@ -54,4 +54,5 @@
 	gerror.c		\
 	gfileutils.c		\
+	gfilewrappers.c		\
 	ghash.c			\
 	ghook.c			\
@@ -123,4 +124,5 @@
 	gerror.h	\
 	gfileutils.h	\
+	gfilewrappers.h	\
 	ghash.h		\
 	ghook.h		\
Index: glib/gtypes.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gtypes.h,v
retrieving revision 1.18
diff -u -2 -r1.18 gtypes.h
--- glib/gtypes.h	2 Aug 2004 22:24:17 -0000	1.18
+++ glib/gtypes.h	21 Aug 2004 21:05:57 -0000
@@ -394,4 +394,9 @@
 };
 
+/* On Unix, the bytes of a file name, literally as it
+ * is in the file system. On Windows, a file's Unicode name, in UTF-8.
+ */
+typedef gchar *GFilename;
+
 G_END_DECLS
 
Index: glib/gconvert.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gconvert.c,v
retrieving revision 1.58
diff -u -2 -r1.58 gconvert.c
--- glib/gconvert.c	2 Aug 2004 15:34:30 -0000	1.58
+++ glib/gconvert.c	21 Aug 2004 21:05:57 -0000
@@ -1184,4 +1184,162 @@
 }
 
+/**
+ * g_filename_to_gfilename:
+ * @opsysstring:   a string in the encoding for filenames
+ * @len:           the length of the string, or -1 if the string is
+ *                 nul-terminated.
+ * @bytes_read:    location to store the number of bytes in the
+ *                 input string that were successfully converted, or %NULL.
+ *                 Even if the conversion was successful, this may be 
+ *                 less than @len if there were partial characters
+ *                 at the end of the input. If the error
+ *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
+ *                 stored will the byte offset after the last valid
+ *                 input sequence.
+ * @bytes_written: the number of bytes stored in the output buffer (not 
+ *                 including the terminating nul).
+ * @error:         location to store the error occuring, or %NULL to ignore
+ *                 errors. Any of the errors in #GConvertError may occur.
+ * 
+ * Converts a string which is in the encoding used for filenames
+ * into the GFilename encoding.
+ * 
+ * Return value: The converted string, or %NULL on an error.
+ **/
+GFilename
+g_filename_to_gfilename (const gchar *opsysstring, 
+			 gssize       len,           
+			 gsize       *bytes_read,   
+			 gsize       *bytes_written,
+			 GError     **error)
+{
+#ifdef G_OS_WIN32
+  return g_filename_to_utf8 (opsysstring, len, bytes_read, bytes_written, error);
+#else
+  if (len < 0)
+    return g_strdup (opsysstring);
+  else
+    return g_strndup (opsysstring, len);
+#endif
+}
+
+/**
+ * g_filename_from_gfilename:
+ * @utf8string:    a GFilename-encoded string.
+ * @len:           the length of the string, or -1 if the string is
+ *                 nul-terminated.
+ * @bytes_read:    location to store the number of bytes in the
+ *                 input string that were successfully converted, or %NULL.
+ *                 Even if the conversion was successful, this may be 
+ *                 less than @len if there were partial characters
+ *                 at the end of the input. If the error
+ *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
+ *                 stored will the byte offset after the last valid
+ *                 input sequence.
+ * @bytes_written: the number of bytes stored in the output buffer (not 
+ *                 including the terminating nul).
+ * @error:         location to store the error occuring, or %NULL to ignore
+ *                 errors. Any of the errors in #GConvertError may occur.
+ * 
+ * Converts a string from UTF-8 to the encoding used for filenames.
+ * 
+ * Return value: The converted string, or %NULL on an error.
+ **/
+gchar*
+g_filename_from_gfilename (GFilename  gfilename,
+			   gssize     len,            
+			   gsize     *bytes_read,    
+			   gsize     *bytes_written,
+			   GError   **error)
+{
+#ifdef G_OS_WIN32
+  return g_filename_from_utf8 (gfilename, len, bytes_read, bytes_written, error);
+#else
+  if (len < 0)
+    return g_strdup (gfilename);
+  else
+    return g_strndup (gfilename, len);
+#endif
+}
+
+/**
+ * g_gfilename_to_utf8:
+ * @opsysstring:   a string in the GFilename encoding
+ * @len:           the length of the string, or -1 if the string is
+ *                 nul-terminated.
+ * @bytes_read:    location to store the number of bytes in the
+ *                 input string that were successfully converted, or %NULL.
+ *                 Even if the conversion was successful, this may be 
+ *                 less than @len if there were partial characters
+ *                 at the end of the input. If the error
+ *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
+ *                 stored will the byte offset after the last valid
+ *                 input sequence.
+ * @bytes_written: the number of bytes stored in the output buffer (not 
+ *                 including the terminating nul).
+ * @error:         location to store the error occuring, or %NULL to ignore
+ *                 errors. Any of the errors in #GConvertError may occur.
+ * 
+ * Converts a string which is in the encoding used for filenames
+ * into a UTF-8 string.
+ * 
+ * Return value: The converted string, or %NULL on an error.
+ **/
+gchar*
+g_gfilename_to_utf8 (GFilename  gfilename, 
+		     gssize     len,           
+		     gsize     *bytes_read,   
+		     gsize     *bytes_written,
+		     GError   **error)
+{
+#ifdef G_OS_WIN32
+  if (len < 0)
+    return g_strdup (gfilename);
+  else
+    return g_strndup (gfilename, len);
+#else
+  return g_filename_to_utf8 (gfilename, len, bytes_read, bytes_written, error);
+#endif
+}
+
+/**
+ * g_gfilename_from_utf8:
+ * @utf8string:    a UTF-8 encoded string.
+ * @len:           the length of the string, or -1 if the string is
+ *                 nul-terminated.
+ * @bytes_read:    location to store the number of bytes in the
+ *                 input string that were successfully converted, or %NULL.
+ *                 Even if the conversion was successful, this may be 
+ *                 less than @len if there were partial characters
+ *                 at the end of the input. If the error
+ *                 #G_CONVERT_ERROR_ILLEGAL_SEQUENCE occurs, the value
+ *                 stored will the byte offset after the last valid
+ *                 input sequence.
+ * @bytes_written: the number of bytes stored in the output buffer (not 
+ *                 including the terminating nul).
+ * @error:         location to store the error occuring, or %NULL to ignore
+ *                 errors. Any of the errors in #GConvertError may occur.
+ * 
+ * Converts a string from UTF-8 to the GFilename encoding.
+ * 
+ * Return value: The converted string, or %NULL on an error.
+ **/
+GFilename
+g_gfilename_from_utf8 (const gchar *utf8string,
+		       gssize       len,            
+		       gsize       *bytes_read,    
+		       gsize       *bytes_written,
+		       GError     **error)
+{
+#ifdef G_OS_WIN32
+  if (len < 0)
+    return g_strdup (utf8string);
+  else
+    return g_strndup (utf8string, len);
+#else
+  return g_filename_from_utf8 (utf8string, len, bytes_read, bytes_written, error);
+#endif
+}
+
 /* Test of haystack has the needle prefix, comparing case
  * insensitive. haystack may be UTF-8, but needle must
Index: glib/gconvert.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gconvert.h,v
retrieving revision 1.13
diff -u -2 -r1.13 gconvert.h
--- glib/gconvert.h	29 Jul 2003 18:59:23 -0000	1.13
+++ glib/gconvert.h	21 Aug 2004 21:05:57 -0000
@@ -96,6 +96,14 @@
 			   GError      **error);
 
-/* Convert between the operating system (or C runtime)
- * representation of file names and UTF-8.
+/* Conversions between the three encodings for file names:
+ * - The one accepted and returned by the C runtime. On Unix this is
+ *   the on-disk bytes of the file names, and one can never be sure
+ *   character set it actually is. On Windows, this is the system
+ *   codepage, either a single byte one like codepage 1252 (mostly ISO
+ *   Latin-1), or a double-byte one like codepage 932 (Japanese),
+ *   where some characters take two bytes.
+ * - GFilename, which is the same as the C runtime one on Unix, and UTF-8
+ *   on Windows.
+ * - UTF-8.
  */
 gchar* g_filename_to_utf8   (const gchar  *opsysstring,
@@ -118,4 +126,26 @@
 			    GError     **error);
 
+
+GFilename g_filename_to_gfilename (const gchar  *opsysstring,
+				   gssize        len,            
+				   gsize        *bytes_read,     
+				   gsize        *bytes_written,  
+				   GError      **error);
+gchar* g_filename_from_gfilename  (GFilename    gfilename,
+				   gssize        len,            
+				   gsize        *bytes_read,     
+				   gsize        *bytes_written,  
+				   GError      **error);
+
+gchar* g_gfilename_to_utf8   	(GFilename     gfilename,
+			     	 gssize        len,            
+			     	 gsize        *bytes_read,     
+			     	 gsize        *bytes_written,  
+			     	 GError      **error);
+GFilename g_gfilename_from_utf8 (const gchar  *utf8string,
+				 gssize        len,            
+				 gsize        *bytes_read,     
+				 gsize        *bytes_written,  
+				 GError      **error);
 
 G_END_DECLS
Index: glib/gdir.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.c,v
retrieving revision 1.10
diff -u -2 -r1.10 gdir.c
--- glib/gdir.c	9 Jul 2004 13:05:40 -0000	1.10
+++ glib/gdir.c	21 Aug 2004 21:05:57 -0000
@@ -5,4 +5,5 @@
  *
  * Copyright 2001 Hans Breuer
+ * Copyright 2004 Tor Lillqvist
  *
  * This library is free software; you can redistribute it and/or
@@ -37,7 +38,21 @@
 #include "glibintl.h"
 
+#ifdef G_OS_UNIX
+#ifdef NAME_MAX
+#define FILENAME_MAX NAME_MAX
+#else
+#define FILANAME_MAX 256
+#endif
+#endif
+
 struct _GDir
 {
-  DIR *dir;
+  gchar utf8_buf[FILENAME_MAX*4];
+  union {
+    DIR *dirp;
+#ifdef G_OS_WIN32
+    _WDIR *wdirp;
+#endif
+  } u;
 };
 
@@ -50,7 +65,7 @@
  *         g_dir_open_fails.
  *
- * Opens a directory for reading. The names of the files
- * in the directory can then be retrieved using
- * g_dir_read_name().
+ * Opens a directory for reading. The names of the files in the
+ * directory can then be retrieved using g_dir_read_name() or
+ * g_dir_read_name_utf8().
  *
  * Return value: a newly allocated #GDir on success, %NULL on failure.
@@ -68,9 +83,24 @@
   g_return_val_if_fail (path != NULL, NULL);
 
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      dir = NULL;
+
+      utf8_path = g_filename_to_utf8 (path, -1, NULL, NULL, error);
+      if (utf8_path != NULL)
+	dir = g_dir_open_gfilename (utf8_path, flags, error);
+      
+      g_free (utf8_path);
+      
+      return dir;
+    }
+#endif
+
   dir = g_new (GDir, 1);
 
-  dir->dir = opendir (path);
+  dir->u.dirp = opendir (path);
 
-  if (dir->dir)
+  if (dir->u.dirp)
     return dir;
 
@@ -91,13 +121,87 @@
 
 /**
+ * g_dir_open_gfilename:
+ * @gfilename: the path to the directory you are interested in. On Unix
+ *         in the on-disk encoding. On Windows in UTF-8
+ * @flags: Currently must be set to 0. Reserved for future use.
+ * @error: return location for a #GError, or %NULL.
+ *         If non-%NULL, an error will be set if and only if
+ *         g_dir_open_fails.
+ *
+ * Opens a directory for reading. The names of the files in the
+ * directory can then be retrieved using g_dir_read_name() or
+ * g_dir_read_gfilename().
+ *
+ * Return value: a newly allocated #GDir on success, %NULL on failure.
+ *   If non-%NULL, you must free the result with g_dir_close()
+ *   when you are finished with it.
+ *
+ * Since: 2.6
+ **/
+GDir *
+g_dir_open_gfilename (GFilename  gpath,
+		      guint      flags,
+		      GError   **error)
+{
+  GDir *dir = NULL;
+
+  g_return_val_if_fail (gpath != NULL, NULL);
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wpath = g_utf8_to_utf16 (gpath, -1, NULL, NULL, error);
+  
+      if (wpath == NULL)
+	return NULL;
+
+      dir = g_new (GDir, 1);
+
+      dir->u.wdirp = _wopendir (wpath);
+      g_free (wpath);
+  
+      if (dir->u.wdirp)
+	return dir;
+
+      /* error case */
+
+      g_set_error (error,
+		   G_FILE_ERROR,
+		   g_file_error_from_errno (errno),
+		   _("Error opening directory '%s': %s"),
+		   gpath, g_strerror (errno));
+
+      g_free (dir);
+      
+      return NULL;
+    }
+  else
+    {
+      gchar *filename = g_filename_from_gfilename (gpath, -1, NULL, NULL, error);
+      if (filename == NULL)
+	return NULL;
+
+      dir = g_dir_open (filename, flags, error);
+
+      g_free (filename);
+
+      return dir;
+    }
+#else
+  return g_dir_open (gpath, flags, error);
+#endif
+}
+
+/**
  * g_dir_read_name:
- * @dir: a #GDir* created by g_dir_open()
+ * @dir: a #GDir* created by g_dir_open() or g_dir_open_gfilename()
  *
- * Retrieves the name of the next entry in the directory.
- * The '.' and '..' entries are omitted. The returned name is in 
- * the encoding used for filenames. Use g_filename_to_utf8() to 
- * convert it to UTF-8.
+ * Retrieves the name of the next entry in the directory.  The '.' and
+ * '..' entries are omitted. The returned name is in the encoding used
+ * for filenames. On Windows, entries whose name can't be expressed in
+ * the system codepage are omitted. Use g_dir_read_gfilename() to
+ * retrieve all names.
  *
- * Return value: The entries name or %NULL if there are no 
+ * Return value: The entry's name or %NULL if there are no 
  *   more entries. The return value is owned by GLib and
  *   must not be modified or freed.
@@ -110,9 +214,40 @@
   g_return_val_if_fail (dir != NULL, NULL);
 
-  entry = readdir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      GFilename gfilename;
+      gchar *name;
+
+      while (1)
+	{
+	  gfilename = g_dir_read_gfilename (dir);
+      
+	  if (gfilename == NULL)
+	    return NULL;
+	  
+	  name = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+	  
+	  if (name == NULL)
+	    continue;		/* Skip names not expressible in the
+				 * system codepage.
+				 */
+
+	  /* UTF-8 strings are never shorter than their system
+	   * codepage equivalents, so it must fit.
+	   */
+	  strcpy (dir->utf8_buf, name);
+	  g_free (name);
+	  
+	  return dir->utf8_buf;
+	}
+    }
+#endif  
+
+  entry = readdir (dir->u.dirp);
   while (entry 
          && (0 == strcmp (entry->d_name, ".") ||
              0 == strcmp (entry->d_name, "..")))
-    entry = readdir (dir->dir);
+    entry = readdir (dir->u.dirp);
 
   if (entry)
@@ -123,9 +258,84 @@
 
 /**
+ * g_dir_read_gfilename:
+ * @dir: a #GDir* created by g_dir_open() or g_dir_open_gfilename()
+ *
+ * Retrieves the name of the next entry in the directory.  The '.' and
+ * '..' entries are omitted. On Windows, the returned name is in
+ * UTF-8. On Unix, it is in the on-disk encoding.
+ *
+ * Return value: The entry's name or %NULL if there are no 
+ *   more entries. The return value is owned by GLib and
+ *   must not be modified or freed.
+ *
+ * Since: 2.6
+ **/
+G_CONST_RETURN GFilename
+g_dir_read_gfilename (GDir *dir)
+{
+
+  g_return_val_if_fail (dir != NULL, NULL);
+
+#ifdef G_OS_WIN32
+
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      gchar *name_utf8;
+      struct _wdirent *entry;
+
+      while (1)
+	{
+	  entry = _wreaddir (dir->u.wdirp);
+	  while (entry 
+		 && (0 == wcscmp (entry->d_name, L".") ||
+		     0 == wcscmp (entry->d_name, L"..")))
+	    entry = _wreaddir (dir->u.wdirp);
+	  
+	  if (entry == NULL)
+	    return NULL;
+	  
+	  name_utf8 = g_utf16_to_utf8 (entry->d_name, -1, NULL, NULL, NULL);
+
+	  if (name_utf8 == NULL)
+	    continue;		/* Huh, impossible? Skip it anyway */
+	  
+	  strcpy (dir->utf8_buf, name_utf8);
+	  g_free (name_utf8);
+	  
+	  return dir->utf8_buf;
+	}
+    }
+  else
+    {
+      while (1)
+	{
+	  gchar *name_utf8;
+	  const gchar *name = g_dir_read_name (dir);
+
+	  if (name == NULL)
+	    return NULL;
+
+	  name_utf8 = g_filename_to_utf8 (name, -1, NULL, NULL, NULL);
+	  
+	  if (name_utf8 != NULL)
+	    {
+	      strcpy (dir->utf8_buf, name_utf8);
+	      g_free (name_utf8);
+	      
+	      return dir->utf8_buf;
+	    }
+	}
+    }
+#else
+  return g_dir_read_name (dir);
+#endif
+}
+
+/**
  * g_dir_rewind:
- * @dir: a #GDir* created by g_dir_open()
+ * @dir: a #GDir* created by g_dir_open() or g_dir_open_utf8()
  *
- * Resets the given directory. The next call to g_dir_read_name()
- * will return the first entry again.
+ * Resets the given directory. The next call to g_dir_read_name() or
+ * g_dir_read_name_utf8() will return the first entry again.
  **/
 void
@@ -134,10 +344,18 @@
   g_return_if_fail (dir != NULL);
   
-  rewinddir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      _wrewinddir (dir->u.wdirp);
+      return;
+    }
+#endif
+
+  rewinddir (dir->u.dirp);
 }
 
 /**
  * g_dir_close:
- * @dir: a #GDir* created by g_dir_open()
+ * @dir: a #GDir* created by g_dir_open() or g_dir_open_utf8()
  *
  * Closes the directory and deallocates all related resources.
@@ -148,5 +366,14 @@
   g_return_if_fail (dir != NULL);
 
-  closedir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      _wclosedir (dir->u.wdirp);
+      g_free (dir);
+      return;
+    }
+#endif
+
+  closedir (dir->u.dirp);
   g_free (dir);
 }
Index: glib/gdir.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.h,v
retrieving revision 1.3
diff -u -2 -r1.3 gdir.h
--- glib/gdir.h	22 Nov 2002 23:45:32 -0000	1.3
+++ glib/gdir.h	21 Aug 2004 21:05:58 -0000
@@ -30,10 +30,14 @@
 typedef struct _GDir GDir;
 
-GDir    *               g_dir_open      (const gchar  *path,
-					 guint         flags,
-					 GError      **error);
-G_CONST_RETURN gchar   *g_dir_read_name (GDir         *dir);
-void                    g_dir_rewind    (GDir         *dir);
-void                    g_dir_close     (GDir         *dir);
+GDir    *                g_dir_open           (const gchar  *path,
+					       guint         flags,
+					       GError      **error);
+GDir    *                g_dir_open_gfilename (GFilename     gpath,
+					       guint         flags,
+					       GError      **error);
+G_CONST_RETURN gchar    *g_dir_read_name      (GDir         *dir);
+G_CONST_RETURN GFilename g_dir_read_gfilename (GDir         *dir);
+void                     g_dir_rewind         (GDir         *dir);
+void                     g_dir_close          (GDir         *dir);
 
 G_END_DECLS
Index: glib/gfileutils.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gfileutils.c,v
retrieving revision 1.43
diff -u -2 -r1.43 gfileutils.c
--- glib/gfileutils.c	14 Dec 2003 19:05:29 -0000	1.43
+++ glib/gfileutils.c	21 Aug 2004 21:05:58 -0000
@@ -182,4 +182,85 @@
 }
 
+/**
+ * g_file_test_gfilename:
+ * @filename_utf8: a filename to test
+ * @test: bitfield of #GFileTest flags
+ * 
+ * Like g_file_test, but takes the filename in UTF-8
+ *    on Windows, in the literal on-disk encoding on Unix.
+ * Return value: whether a test was %TRUE
+ *
+ * Since: 2.6
+ **/
+gboolean
+g_file_test_gfilename (const gchar *gfilename,
+		       GFileTest    test)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+
+      if (wfilename == NULL)
+	return FALSE;
+
+      if ((test & G_FILE_TEST_EXISTS) && (_waccess (wfilename, F_OK) == 0))
+	{
+	  g_free (wfilename);
+	  return TRUE;
+	}
+      
+      if (test & (G_FILE_TEST_IS_REGULAR |
+		  G_FILE_TEST_IS_DIR |
+		  G_FILE_TEST_IS_EXECUTABLE))
+	{
+	  struct _stat s;
+	  
+	  if (_wstat (wfilename, &s) == 0)
+	    {
+	      if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
+		{
+		  g_free (wfilename);
+		  return TRUE;
+		}
+	      
+	      if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
+		{
+		  g_free (wfilename);
+		  return TRUE;
+		}
+	      
+	      if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
+		  (s.st_mode & _S_IEXEC))
+		{
+		  g_free (wfilename);
+		  return TRUE;
+		}
+	    }
+	}
+
+      g_free (wfilename);
+      
+      return FALSE;
+    }
+  else
+    {
+      gchar *filename = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+      gboolean retval;
+
+      if (filename == NULL)
+	return FALSE;
+      
+      retval = g_file_test (filename, test);
+
+      g_free (filename);
+
+      return retval;
+    }
+#else
+  return g_file_test (gfilename, test);
+#endif
+}
+
 GQuark
 g_file_error_quark (void)
@@ -357,5 +438,5 @@
 
 static gboolean
-get_contents_stdio (const gchar *filename,
+get_contents_stdio (const gchar *utf8_filename,
                     FILE        *f,
                     gchar      **contents,
@@ -392,5 +473,5 @@
                            G_FILE_ERROR_NOMEM,
                            _("Could not allocate %lu bytes to read file \"%s\""),
-                           (gulong) total_allocated, filename);
+                           (gulong) total_allocated, utf8_filename);
               goto error;
             }
@@ -403,5 +484,5 @@
                        g_file_error_from_errno (errno),
                        _("Error reading file '%s': %s"),
-                       filename, g_strerror (errno));
+                       utf8_filename, g_strerror (errno));
 
           goto error;
@@ -434,5 +515,5 @@
 
 static gboolean
-get_contents_regfile (const gchar *filename,
+get_contents_regfile (const gchar *utf8_filename,
                       struct stat *stat_buf,
                       gint         fd,
@@ -457,5 +538,5 @@
                    G_FILE_ERROR_NOMEM,
                    _("Could not allocate %lu bytes to read file \"%s\""),
-                   (gulong) alloc_size, filename);
+                   (gulong) alloc_size, utf8_filename);
 
       goto error;
@@ -479,5 +560,5 @@
                            g_file_error_from_errno (errno),
                            _("Failed to read from file '%s': %s"),
-                           filename, g_strerror (errno));
+                           utf8_filename, g_strerror (errno));
 
 	      goto error;
@@ -516,5 +597,8 @@
   struct stat stat_buf;
   gint fd;
+  gchar *utf8_filename;
   
+  utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+
   /* O_BINARY useful on Cygwin */
   fd = open (filename, O_RDONLY|O_BINARY);
@@ -526,5 +610,6 @@
                    g_file_error_from_errno (errno),
                    _("Failed to open file '%s': %s"),
-                   filename, g_strerror (errno));
+                   utf8_filename, g_strerror (errno));
+      g_free (utf8_filename);
 
       return FALSE;
@@ -540,5 +625,6 @@
                    g_file_error_from_errno (errno),
                    _("Failed to get attributes of file '%s': fstat() failed: %s"),
-                   filename, g_strerror (errno));
+                   utf8_filename, g_strerror (errno));
+      g_free (utf8_filename);
 
       return FALSE;
@@ -547,14 +633,18 @@
   if (stat_buf.st_size > 0 && S_ISREG (stat_buf.st_mode))
     {
-      return get_contents_regfile (filename,
-                                   &stat_buf,
-                                   fd,
-                                   contents,
-                                   length,
-                                   error);
+      gboolean retval = get_contents_regfile (utf8_filename,
+					      &stat_buf,
+					      fd,
+					      contents,
+					      length,
+					      error);
+      g_free (utf8_filename);
+
+      return retval;
     }
   else
     {
       FILE *f;
+      gboolean retval;
 
       f = fdopen (fd, "r");
@@ -566,10 +656,14 @@
                        g_file_error_from_errno (errno),
                        _("Failed to open file '%s': fdopen() failed: %s"),
-                       filename, g_strerror (errno));
+                       utf8_filename, g_strerror (errno));
+	  g_free (utf8_filename);
           
           return FALSE;
         }
   
-      return get_contents_stdio (filename, f, contents, length, error);
+      retval = get_contents_stdio (utf8_filename, f, contents, length, error);
+      g_free (utf8_filename);
+
+      return retval;
     }
 }
@@ -584,4 +678,8 @@
 {
   FILE *f;
+  gchar *utf8_filename;
+  gboolean retval;
+  
+  utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
 
   /* I guess you want binary mode; maybe you want text sometimes? */
@@ -594,10 +692,43 @@
                    g_file_error_from_errno (errno),
                    _("Failed to open file '%s': %s"),
-                   filename, g_strerror (errno));
+                   utf8_filename, g_strerror (errno));
+      g_free (utf8_filename);
       
       return FALSE;
     }
   
-  return get_contents_stdio (filename, f, contents, length, error);
+  retval = get_contents_stdio (utf8_filename, f, contents, length, error);
+  g_free (utf8_filename);
+
+  return retval;
+}
+
+static gboolean
+get_contents_win32_gfilename (const gchar *gfilename,
+			      gchar      **contents,
+			      gsize       *length,
+			      GError     **error)
+{
+  FILE *f;
+  gboolean retval;
+  wchar_t *wfilename = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+  
+  f = _wfopen (wfilename, L"rb");
+  g_free (wfilename);
+
+  if (f == NULL)
+    {
+      g_set_error (error,
+                   G_FILE_ERROR,
+                   g_file_error_from_errno (errno),
+                   _("Failed to open file '%s': %s"),
+                   gfilename, g_strerror (errno));
+      
+      return FALSE;
+    }
+  
+  retval = get_contents_stdio (gfilename, f, contents, length, error);
+
+  return retval;
 }
 
@@ -606,5 +737,5 @@
 /**
  * g_file_get_contents:
- * @filename: a file to read contents from
+ * @filename: name of a file to read contents from, in the encoding used for filenames
  * @contents: location to store an allocated string
  * @length: location to store length in bytes of the contents
@@ -641,4 +772,50 @@
 }
 
+/**
+ * g_file_get_contents_gfilename:
+ *
+ * Like g_file_get_contents, but takes the file name in UTF-8 on Windows,
+ * and in the on-disk encoding on Unix.
+ *
+ * Return value: %TRUE on success, %FALSE if error is set
+ *
+ * Since: 2.6
+ **/
+gboolean
+g_file_get_contents_gfilename (const gchar *gfilename,
+			       gchar      **contents,
+			       gsize       *length,
+			       GError     **error)
+{  
+#ifdef G_OS_WIN32
+  gchar *filename;
+  gboolean retval;
+#endif
+
+  g_return_val_if_fail (gfilename != NULL, FALSE);
+  g_return_val_if_fail (contents != NULL, FALSE);
+
+  *contents = NULL;
+  if (length)
+    *length = 0;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    return get_contents_win32_gfilename (gfilename, contents, length, error);
+
+  filename = g_filename_from_utf8 (gfilename, -1, NULL, NULL, error);
+
+  if (filename == NULL)
+    return FALSE;
+  
+  retval = get_contents_win32 (filename, contents, length, error);
+  g_free (filename);
+
+  return retval;
+#else
+  return get_contents_posix (gfilename, contents, length, error);
+#endif
+}
+
 /*
  * mkstemp() implementation is from the GNU C library.
@@ -1147,4 +1324,5 @@
       read_size = readlink (filename, buffer, size);
       if (read_size < 0) {
+	gchar *utf8_filename = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
 	g_free (buffer);
 	g_set_error (error,
@@ -1152,5 +1330,6 @@
 		     g_file_error_from_errno (errno),
 		     _("Failed to read the symbolic link '%s': %s"),
-		     filename, g_strerror (errno));
+		     utf8_filename, g_strerror (errno));
+	g_free (utf8_filename);
 	
 	return NULL;
@@ -1174,3 +1353,18 @@
   return NULL;
 #endif
+}
+
+/**
+ * g_file_read_link_gfilename:
+ *
+ * Functionally identical to g_file_read_link(), present just for
+ * ortogonality.
+ *
+ * Since: 2.6
+ */
+gchar *
+g_file_read_link_gfilename (const gchar *gfilename,
+			    GError     **error)
+{
+  return g_file_read_link (gfilename, error);
 }
Index: glib/gfileutils.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gfileutils.h,v
retrieving revision 1.12
diff -u -2 -r1.12 gfileutils.h
--- glib/gfileutils.h	29 Jul 2003 22:31:39 -0000	1.12
+++ glib/gfileutils.h	21 Aug 2004 21:05:58 -0000
@@ -96,7 +96,22 @@
 			 ...);
 
-G_END_DECLS
+/* GFilename versions */
 
-#endif /* __G_FILEUTILS_H__ */
+gboolean g_file_test_gfilename         (const gchar  *gfilename,
+				  	GFileTest     test);
+gboolean g_file_get_contents_gfilename (const gchar  *gfilename,
+					gchar       **contents,
+					gsize        *length,    
+					GError      **error);
+gchar   *g_file_read_link_gfilename    (const gchar  *gfilename,
+					GError      **error);
 
+gint    g_mkstemp_gfilename            (gchar        *tmpl_gfilename);
+     
+gint    g_file_open_tmp_gfilename      (const gchar  *tmpl_gfilename,
+				  	gchar       **name_used_gfilename,
+				  	GError      **error);
 
+G_END_DECLS
+
+#endif /* __G_FILEUTILS_H__ */
Index: glib/gwin32.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gwin32.c,v
retrieving revision 1.38
diff -u -2 -r1.38 gwin32.c
--- glib/gwin32.c	25 Apr 2004 22:51:46 -0000	1.38
+++ glib/gwin32.c	21 Aug 2004 21:05:59 -0000
@@ -1298,2 +1298,18 @@
   return dirname;
 }
+
+guint
+g_win32_get_windows_version (void)
+{
+  static gboolean beenhere = FALSE;
+  static guint version;
+
+  if (!beenhere)
+    {
+      version = GetVersion ();
+      if (getenv ("PRETEND_WIN9X"))
+	version = 0x80000004;
+      beenhere = TRUE;
+    }
+  return version;
+}
Index: glib/gwin32.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gwin32.h,v
retrieving revision 1.9
diff -u -2 -r1.9 gwin32.h
--- glib/gwin32.h	2 Jan 2003 00:30:22 -0000	1.9
+++ glib/gwin32.h	21 Aug 2004 21:05:59 -0000
@@ -94,4 +94,8 @@
 							       gchar *subdir);
 
+guint		g_win32_get_windows_version (void);
+
+#define G_WIN32_HAVE_WIDECHAR_API() (g_win32_get_windows_version () < 0x80000000)
+
 G_END_DECLS
 
--- /dev/null	2004-08-21 21:30:29.984000000 +0000
+++ glib/gfilewrappers.c	2004-08-21 21:26:03.140468800 +0000
@@ -0,0 +1,242 @@
+/* gfilewrappers.c - GFilename wrappers for C library functions
+ *
+ * Copyright 2004 Tor Lillqvist
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include "glib.h"
+#include "gfilewrappers.h"
+
+#ifdef G_OS_UNIX
+#include <unistd.h>
+#endif
+
+#ifdef G_OS_WIN32
+#include <wchar.h>
+#include <io.h>
+#endif
+
+#if !defined (G_OS_UNIX) && !defined (G_OS_WIN32)
+#error Please port this to your operating system
+#endif
+
+#include <sys/stat.h>
+
+int
+g_open (GFilename gfilename,
+	int       flags,
+	int       mode)
+{
+  gchar *pathname;
+  int retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *pathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      int retval = _wopen (pathname, flags, mode);
+      
+      g_free (pathname);
+
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+  retval = open (pathname, flags, mode);
+
+  g_free (pathname);
+
+  return retval;
+}
+
+int
+g_rename (GFilename oldgfilename,
+	  GFilename newgfilename)
+{
+  gchar *oldpath;
+  gchar *newpath;
+  int retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *oldwpath = g_utf8_to_utf16 (oldgfilename, -1, NULL, NULL, NULL);
+      wchar_t *newwpath = g_utf8_to_utf16 (newgfilename, -1, NULL, NULL, NULL);
+      int retval = _wrename (oldwpath, newwpath);
+      
+      g_free (oldwpath);
+      g_free (newwpath);
+      
+      return retval;
+    }
+#endif
+
+  oldpath = g_filename_from_gfilename (oldgfilename, -1, NULL, NULL, NULL);
+  newpath = g_filename_from_gfilename (newgfilename, -1, NULL, NULL, NULL);
+  retval = rename (oldpath, newpath);
+
+  g_free (oldpath);
+  g_free (newpath);
+
+  return retval;
+}
+
+int
+g_mkdir (GFilename gfilename,
+	 int       mode)
+{
+  gchar *pathname;
+  int retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *wpathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      int retval = _wmkdir (wpathname);
+      
+      g_free (wpathname);
+      
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+#ifdef G_OS_WIN32
+  retval = mkdir (pathname);
+#else
+  retval = mkdir (pathname, mode);
+#endif
+
+  g_free (pathname);
+
+  return retval;
+}
+
+int
+g_stat (GFilename    gfilename,
+	struct stat *buf)
+{
+  gchar *pathname;
+  int retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *wpathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      int retval = _wstat (wpathname, (struct _stat *) buf);
+
+      g_free (wpathname);
+
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+  retval = stat (pathname, buf);
+
+  g_free (pathname);
+
+  return retval;
+}
+
+int
+g_unlink (GFilename gfilename)
+{
+  gchar *pathname;
+  int retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *wpathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      int retval = _wunlink (wpathname);
+  
+      g_free (wpathname);
+
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+  retval = unlink (pathname);
+
+  g_free (pathname);
+
+  return retval;
+}
+
+FILE *
+g_fopen (GFilename    gfilename,
+	 const gchar *mode)
+{
+  gchar *pathname;
+  FILE *retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *wpathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfopen (wpathname, wmode);
+
+      g_free (wpathname);
+      g_free (wmode);
+
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+  retval = fopen (pathname, mode);
+
+  g_free (pathname);
+
+  return retval;
+}
+
+FILE *
+g_freopen (GFilename    gfilename,
+	   const gchar *mode,
+	   FILE        *stream)
+{
+  gchar *pathname;
+  FILE *retval;
+
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAS_WIDECHAR_API ())
+    {
+      wchar_t *wpathname = g_utf8_to_utf16 (gfilename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfreopen (wpathname, wmode, stream);
+
+      g_free (wpathname);
+      g_free (wmode);
+
+      return retval;
+    }
+#endif
+
+  pathname = g_filename_from_gfilename (gfilename, -1, NULL, NULL, NULL);
+  retval = freopen (pathname, mode, stream);
+
+  g_free (pathname);
+
+  return retval;
+}
--- /dev/null	2004-08-21 21:30:32.678000000 +0000
+++ glib/gfilewrappers.h	2004-08-21 21:22:50.863988800 +0000
@@ -0,0 +1,55 @@
+/* gfilewrappers.h - GFilename wrappers for C library functions
+ *
+ * Copyright 2004 Tor Lillqvist
+ *
+ * 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.
+ */
+
+#ifndef __G_FILEWRAPPERS_H__
+#define __G_FILEWRAPPERS_H__
+
+#include <stdio.h>
+#include <sys/stat.h>
+
+/* Wrappers for C library functions that take pathname arguments as
+ * GFilename. On Unix, this means just the file name as it literally
+ * is in the file system. On Windows, it's the file name in UTF-8.
+ */
+
+int g_open      (GFilename    gfilename,
+                 int          flags,
+                 int          mode);
+                     
+int g_rename    (GFilename    oldgfilename,
+                 GFilename    newgfilename);
+                     
+                     
+int g_mkdir     (GFilename    gfilename,
+                 int          mode);
+                     
+int g_stat      (GFilename    gfilename,
+                 struct stat *buf);
+                     
+int g_unlink    (GFilename    gfilename);
+                     
+FILE *g_fopen   (GFilename    gfilename,
+                 const gchar *mode);
+
+FILE *g_freopen (GFilename    gfilename,
+                 const gchar *mode,
+                 FILE        *stream);
+
+#endif /* __G_FILEWRAPPERS_H__ */
