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	24 Aug 2004 22:54:16 -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/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	24 Aug 2004 22:54:16 -0000
@@ -1089,10 +1089,31 @@
 
 #else /* G_PLATFORM_WIN32 */
+
 static gboolean
 get_filename_charset (const gchar **filename_charset) 
 {
+#ifdef G_OS_WIN32
+  /* On Windows GLib pretends that the filename charset is UTF-8 */
+  if (filename_charset)
+    *filename_charset = "UTF-8";
+  return TRUE;
+#else
+  /* Cygwin works like before */
+  g_get_charset (filename_charset);
+  return FALSE;
+#endif
+}
+
+#ifdef G_OS_WIN32
+
+static gboolean
+old_get_filename_charset (const gchar **filename_charset) 
+{
   g_get_charset (filename_charset);
   return FALSE;
 }
+
+#endif
+
 #endif /* G_PLATFORM_WIN32 */
 
@@ -1146,4 +1167,28 @@
 }
 
+#ifdef G_OS_WIN32
+
+#undef g_filename_to_utf8
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_filename_to_utf8 (const gchar *opsysstring, 
+		    gssize       len,           
+		    gsize       *bytes_read,   
+		    gsize       *bytes_written,
+		    GError     **error)
+{
+  const gchar *charset;
+
+  if (old_get_filename_charset (&charset))
+    return strdup_len (opsysstring, len, bytes_read, bytes_written, error);
+  else
+    return g_convert (opsysstring, len, 
+		      "UTF-8", charset, bytes_read, bytes_written, error);
+}
+
+#endif
+
 /**
  * g_filename_from_utf8:
@@ -1183,4 +1228,28 @@
 		      charset, "UTF-8", bytes_read, bytes_written, error);
 }
+
+#ifdef G_OS_WIN32
+
+#undef g_filename_from_utf8
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_filename_from_utf8 (const gchar *utf8string,
+		      gssize       len,            
+		      gsize       *bytes_read,    
+		      gsize       *bytes_written,
+		      GError     **error)
+{
+  const gchar *charset;
+
+  if (old_get_filename_charset (&charset))
+    return strdup_len (utf8string, len, bytes_read, bytes_written, error);
+  else
+    return g_convert (utf8string, len,
+		      charset, "UTF-8", bytes_read, bytes_written, error);
+}
+
+#endif
 
 /* Test of haystack has the needle prefix, comparing case
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	24 Aug 2004 22:54:16 -0000
@@ -99,4 +99,9 @@
  * representation of file names and UTF-8.
  */
+#ifdef G_OS_WIN32
+#define g_filename_to_utf8 g_filename_to_utf8_utf8
+#define g_filename_from_utf8 g_filename_from_utf8_utf8
+#endif
+
 gchar* g_filename_to_utf8   (const gchar  *opsysstring,
 			     gssize        len,            
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	24 Aug 2004 22:54:17 -0000
@@ -5,4 +5,5 @@
  *
  * Copyright 2001 Hans Breuer
+ * Copyright 2004 Tor Lillqvist
  *
  * This library is free software; you can redistribute it and/or
@@ -39,10 +40,19 @@
 struct _GDir
 {
-  DIR *dir;
+  union {
+    DIR *dirp;
+#ifdef G_OS_WIN32
+    _WDIR *wdirp;
+#endif
+  } u;
+#ifdef G_OS_WIN32
+  gchar utf8_buf[FILENAME_MAX*4];
+#endif
 };
 
 /**
  * g_dir_open:
- * @path: the path to the directory you are interested in
+ * @path: 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.
@@ -50,7 +60,6 @@
  *         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().
  *
  * Return value: a newly allocated #GDir on success, %NULL on failure.
@@ -64,13 +73,60 @@
 {
   GDir *dir;
+#ifndef G_OS_WIN32
   gchar *utf8_path;
+#endif
 
   g_return_val_if_fail (path != NULL, NULL);
 
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wpath = g_utf8_to_utf16 (path, -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;
+    }
+  else
+    {
+      gchar *cp_path = g_locale_from_utf8 (path, -1, NULL, NULL, error);
+
+      if (cp_path == NULL)
+	return NULL;
+
+      dir = g_new (GDir, 1);
+
+      dir->u.dirp = opendir (cp_path);
+
+      g_free (cp_path);
+
+      if (dir->u.dirp)
+	return dir;
+    }
+
+  /* error case */
+
+  g_set_error (error,
+	       G_FILE_ERROR,
+	       g_file_error_from_errno (errno),
+	       _("Error opening directory '%s': %s"),
+	       path, g_strerror (errno));
+  
+  g_free (dir);
+      
+  return NULL;
+#else
   dir = g_new (GDir, 1);
 
-  dir->dir = opendir (path);
+  dir->u.dirp = opendir (path);
 
-  if (dir->dir)
+  if (dir->u.dirp)
     return dir;
 
@@ -88,16 +144,46 @@
 
   return NULL;
+#endif
 }
 
+#ifdef G_OS_WIN32
+
+/* The above function actually is called g_dir_open_utf8, and it's
+ * that what applications compiled with this GLib version will
+ * use.
+ */
+
+#undef g_dir_open
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+GDir *
+g_dir_open (const gchar  *path,
+            guint         flags,
+            GError      **error)
+{
+  gchar *utf8_path = g_locale_to_utf8 (path, -1, NULL, NULL, error);
+  GDir *retval;
+
+  if (utf8_path == NULL)
+    return NULL;
+
+  retval = g_dir_open_utf8 (utf8_path, flags, error);
+
+  g_free (utf8_path);
+
+  return retval;
+}
+#endif
+
 /**
  * g_dir_read_name:
  * @dir: a #GDir* created by g_dir_open()
  *
- * 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. On Windows, the returned name is in
+ * UTF-8. On Unix, it is in the on-disk encoding.
  *
- * 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 +196,64 @@
   g_return_val_if_fail (dir != NULL, NULL);
 
-  entry = readdir (dir->dir);
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      gchar *utf8_name;
+      struct _wdirent *wentry;
+
+      while (1)
+	{
+	  wentry = _wreaddir (dir->u.wdirp);
+	  while (wentry 
+		 && (0 == wcscmp (wentry->d_name, L".") ||
+		     0 == wcscmp (wentry->d_name, L"..")))
+	    wentry = _wreaddir (dir->u.wdirp);
+	  
+	  if (wentry == NULL)
+	    return NULL;
+	  
+	  utf8_name = g_utf16_to_utf8 (wentry->d_name, -1, NULL, NULL, NULL);
+
+	  if (utf8_name == NULL)
+	    continue;		/* Huh, impossible? Skip it anyway */
+	  
+	  strcpy (dir->utf8_buf, utf8_name);
+	  g_free (utf8_name);
+	  
+	  return dir->utf8_buf;
+	}
+    }
+  else
+    {
+      while (1)
+	{
+	  gchar *utf8_name;
+      
+	  entry = readdir (dir->u.dirp);
+	  while (entry 
+		 && (0 == strcmp (entry->d_name, ".") ||
+		     0 == strcmp (entry->d_name, "..")))
+	    entry = readdir (dir->u.dirp);
+
+	  if (entry == NULL)
+	    return NULL;
+
+	  utf8_name = g_locale_to_utf8 (entry->d_name, -1, NULL, NULL, NULL);
+
+	  if (utf8_name != NULL)
+	    {
+	      strcpy (dir->utf8_buf, utf8_name);
+	      g_free (utf8_name);
+	      
+	      return dir->utf8_buf;
+	    }
+	}
+    }
+#else
+  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)
@@ -120,12 +261,46 @@
   else
     return NULL;
+#endif
+}
+
+#ifdef G_OS_WIN32
+
+/* Ditto for g_dir_read_name */
+
+#undef g_dir_read_name
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+G_CONST_RETURN gchar*
+g_dir_read_name (GDir *dir)
+{
+  while (1)
+    {
+      const gchar *utf8_name = g_dir_read_name_utf8 (dir);
+      gchar *retval;
+      
+      if (utf8_name == NULL)
+	return NULL;
+
+      retval = g_locale_from_utf8 (utf8_name, -1, NULL, NULL, NULL);
+
+      if (retval != NULL)
+	{
+	  strcpy (dir->utf8_buf, retval);
+	  g_free (retval);
+
+	  return dir->utf8_buf;
+	}
+    }
 }
 
+#endif
+
 /**
  * g_dir_rewind:
  * @dir: a #GDir* created by g_dir_open()
  *
- * 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() will
+ * return the first entry again.
  **/
 void
@@ -134,5 +309,13 @@
   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);
 }
 
@@ -148,5 +331,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	24 Aug 2004 22:54:17 -0000
@@ -30,10 +30,16 @@
 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);
+#ifdef G_OS_WIN32
+/* For DLL ABI stability, keep old names for old (non-UTF8) functionality. */
+#define g_dir_open g_dir_open_utf8
+#define g_dir_read_name g_dir_read_name_utf8
+#endif
+
+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);
 
 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	24 Aug 2004 22:54:17 -0000
@@ -63,4 +63,5 @@
 #endif
 
+#include "gfilewrappers.h"
 #include "glibintl.h"
 
@@ -100,5 +101,5 @@
  * /&ast; DON'T DO THIS &ast;/
  *  if (!g_file_test (filename, G_FILE_TEST_IS_SYMLINK)) {
- *    fd = open (filename, O_WRONLY);
+ *    fd = g_open (filename, O_WRONLY);
  *    /&ast; write to fd &ast;/
  *  }
@@ -118,8 +119,101 @@
              GFileTest    test)
 {
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -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 *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+
+      if (cp_filename == NULL)
+	return FALSE;
+      
+      if ((test & G_FILE_TEST_EXISTS) && (access (cp_filename, F_OK) == 0))
+	{
+	  g_free (cp_filename);
+	  return TRUE;
+	}
+      
+      if (test & (G_FILE_TEST_IS_REGULAR |
+		  G_FILE_TEST_IS_DIR |
+		  G_FILE_TEST_IS_EXECUTABLE))
+	{
+	  struct stat s;
+	  
+	  if (stat (cp_filename, &s) == 0)
+	    {
+	      if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode))
+		{
+		  g_free (cp_filename);
+		  return TRUE;
+		}
+	      
+	      if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode))
+		{
+		  g_free (cp_filename);
+		  return TRUE;
+		}
+	      
+	      if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
+		  (s.st_mode & _S_IEXEC))
+		{
+		  g_free (cp_filename);
+		  return TRUE;
+		}
+	    }
+	}
+
+      g_free (cp_filename);
+      
+      return FALSE;
+    }
+#else
   if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0))
     return TRUE;
   
-#ifndef G_OS_WIN32
   if ((test & G_FILE_TEST_IS_EXECUTABLE) && (access (filename, X_OK) == 0))
     {
@@ -134,16 +228,11 @@
   else
     test &= ~G_FILE_TEST_IS_EXECUTABLE;
-#endif	
 
   if (test & G_FILE_TEST_IS_SYMLINK)
     {
-#ifdef G_OS_WIN32
-      /* no sym links on win32, no lstat in msvcrt */
-#else
       struct stat s;
 
       if ((lstat (filename, &s) == 0) && S_ISLNK (s.st_mode))
         return TRUE;
-#endif
     }
   
@@ -162,7 +251,5 @@
 	    return TRUE;
 
-#ifndef G_OS_WIN32
 	  /* The extra test for root when access (file, X_OK) succeeds.
-	   * Probably only makes sense on Unix.
 	   */
 	  if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
@@ -171,15 +258,36 @@
 	       (s.st_mode & S_IXGRP)))
 	    return TRUE;
-#else
-	  if ((test & G_FILE_TEST_IS_EXECUTABLE) &&
-	      (s.st_mode & _S_IEXEC))
-	    return TRUE;
-#endif
 	}
     }
 
   return FALSE;
+#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;
 }
 
+#endif
+
 GQuark
 g_file_error_quark (void)
@@ -357,5 +465,5 @@
 
 static gboolean
-get_contents_stdio (const gchar *filename,
+get_contents_stdio (const gchar *utf8_filename,
                     FILE        *f,
                     gchar      **contents,
@@ -392,5 +500,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 +511,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 +542,5 @@
 
 static gboolean
-get_contents_regfile (const gchar *filename,
+get_contents_regfile (const gchar *utf8_filename,
                       struct stat *stat_buf,
                       gint         fd,
@@ -457,5 +565,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 +587,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 +624,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 +637,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 +652,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 +660,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 +683,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;
     }
 }
@@ -579,12 +700,14 @@
 static gboolean
 get_contents_win32 (const gchar *filename,
-                    gchar      **contents,
-                    gsize       *length,
-                    GError     **error)
+		    gchar      **contents,
+		    gsize       *length,
+		    GError     **error)
 {
   FILE *f;
-
-  /* I guess you want binary mode; maybe you want text sometimes? */
-  f = fopen (filename, "rb");
+  gboolean retval;
+  wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+  
+  f = _wfopen (wfilename, L"rb");
+  g_free (wfilename);
 
   if (f == NULL)
@@ -599,5 +722,7 @@
     }
   
-  return get_contents_stdio (filename, f, contents, length, error);
+  retval = get_contents_stdio (filename, f, contents, length, error);
+
+  return retval;
 }
 
@@ -606,5 +731,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 +766,31 @@
 }
 
+#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
+
 /*
  * mkstemp() implementation is from the GNU C library.
@@ -707,5 +859,6 @@
       XXXXXX[5] = letters[v % NLETTERS];
 
-      fd = open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
+      /* tmpl is in UTF-8 on Windows, thus use g_open() */
+      fd = g_open (tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
 
       if (fd >= 0)
@@ -723,4 +876,71 @@
 }
 
+#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
+
 /**
  * g_file_open_tmp:
@@ -824,4 +1044,37 @@
 }
 
+#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
+
 static gchar *
 g_build_pathv (const gchar *separator,
@@ -1147,4 +1400,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 +1406,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;
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	24 Aug 2004 22:54:17 -0000
@@ -73,4 +73,11 @@
 GFileError g_file_error_from_errno (gint err_no);
 
+#ifdef G_OS_WIN32
+#define g_file_test g_file_test_utf8
+#define g_file_get_contents g_file_get_contents_utf8
+#define g_mkstemp g_mkstemp_utf8
+#define g_file_open_tmp g_file_open_tmp_utf8
+#endif
+
 gboolean g_file_test         (const gchar  *filename,
                               GFileTest     test);
@@ -99,4 +106,2 @@
 
 #endif /* __G_FILEUTILS_H__ */
-
-
Index: glib/gutils.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gutils.c,v
retrieving revision 1.136
diff -u -2 -r1.136 gutils.c
--- glib/gutils.c	23 Aug 2004 05:36:48 -0000	1.136
+++ glib/gutils.c	24 Aug 2004 22:54:18 -0000
@@ -710,9 +710,30 @@
     }
 
+#ifdef G_OS_WIN32
+  dir = g_locale_to_utf8 (buffer, -1, NULL, NULL, NULL);
+#else
   dir = g_strdup (buffer);
+#endif
   g_free (buffer);
   
   return dir;
 }
+
+#ifdef G_OS_WIN32
+
+#undef g_get_current_dir
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+gchar*
+g_get_current_dir (void)
+{
+  gchar *utf8_dir = g_get_current_dir_utf8 ();
+  gchar *dir = g_locale_from_utf8 (utf8_dir, -1, NULL, NULL, NULL);
+  g_free (utf8_dir);
+  return dir;
+}
+
+#endif
 
 /**
Index: glib/gutils.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gutils.h,v
retrieving revision 1.21
diff -u -2 -r1.21 gutils.h
--- glib/gutils.h	11 Aug 2004 17:53:05 -0000	1.21
+++ glib/gutils.h	24 Aug 2004 22:54:18 -0000
@@ -168,4 +168,8 @@
 #endif /* G_DISABLE_DEPRECATED */
 
+#ifdef G_OS_WIN32
+#define g_get_current_dir g_get_current_dir_utf8
+#endif
+
 /* The returned strings are newly allocated with g_malloc() */
 gchar*                g_get_current_dir    (void);
Index: glib/giowin32.c
===================================================================
RCS file: /cvs/gnome/glib/glib/giowin32.c,v
retrieving revision 1.57
diff -u -2 -r1.57 giowin32.c
--- glib/giowin32.c	21 Aug 2004 21:29:35 -0000	1.57
+++ glib/giowin32.c	24 Aug 2004 22:54:19 -0000
@@ -46,4 +46,5 @@
 #include <sys/stat.h>
 
+#include "gfilewrappers.h"
 #include "glibintl.h"
 
@@ -1336,5 +1337,5 @@
 
   /* always open 'untranslated' */
-  fid = open (filename, flags | _O_BINARY, pmode);
+  fid = g_open (filename, flags | _O_BINARY, pmode);
 
   if (g_io_win32_get_debug_flag ())
@@ -1382,4 +1383,30 @@
   return channel;
 }
+
+#ifdef G_OS_WIN32
+
+#undef g_io_channel_new_file
+
+/* Binary compatibility version. Not for newly compiled code. */
+
+GIOChannel *
+g_io_channel_new_file (const gchar  *filename,
+                       const gchar  *mode,
+                       GError      **error)
+{
+  gchar *utf8_filename = g_locale_to_utf8 (filename, -1, NULL, NULL, error);
+  GIOChannel *retval;
+
+  if (utf8_filename == NULL)
+    return NULL;
+
+  retval = g_io_channel_new_file_utf8 (utf8_filename, mode, error);
+
+  g_free (utf8_filename);
+
+  return retval;
+}
+
+#endif
 
 static GIOStatus
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	24 Aug 2004 22:54:19 -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	24 Aug 2004 22:54:19 -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
 
Index: glib/glib.def
===================================================================
RCS file: /cvs/gnome/glib/glib/glib.def,v
retrieving revision 1.113
diff -u -2 -r1.113 glib.def
--- glib/glib.def	6 Aug 2004 18:22:46 -0000	1.113
+++ glib/glib.def	24 Aug 2004 22:54:19 -0000
@@ -148,6 +148,8 @@
 	g_date_valid_year
 	g_dir_close
-	g_dir_open
-	g_dir_read_name
+	g_dir_open PRIVATE
+	g_dir_open_utf8
+	g_dir_read_name PRIVATE
+	g_dir_read_name_utf8
 	g_dir_rewind
 	g_direct_equal
@@ -160,12 +162,17 @@
 	g_file_error_from_errno
 	g_file_error_quark
-	g_file_get_contents
-	g_file_open_tmp
+	g_file_get_contents PRIVATE
+	g_file_get_contents_utf8
+	g_file_open_tmp PRIVATE
+	g_file_open_tmp_utf8
 	g_file_read_link
-	g_file_test
+	g_file_test PRIVATE
+	g_file_test_utf8
 	g_filename_from_uri
-	g_filename_from_utf8
+	g_filename_from_utf8 PRIVATE
+	g_filename_from_utf8_utf8
 	g_filename_to_uri
-	g_filename_to_utf8
+	g_filename_to_utf8 PRIVATE
+	g_filename_to_utf8_utf8
 	g_find_program_in_path
 	g_fprintf
@@ -369,5 +376,6 @@
 	g_mem_set_vtable
 	g_memdup
-	g_mkstemp
+	g_mkstemp PRIVATE
+	g_mkstemp_utf8
 	g_node_child_index
 	g_node_child_position
--- /dev/null	2004-08-24 23:18:58.311000000 +0000
+++ glib/gfilewrappers.c	2004-08-23 23:21:47.987521600 +0000
@@ -0,0 +1,303 @@
+/* gfilewrappers.c - 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 (const gchar *filename,
+	int          flags,
+	int          mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wopen (wfilename, flags, mode);
+      int save_errno = errno;
+      
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {    
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = open (cp_filename, flags, mode);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return open (filename, flags, mode);
+#endif
+}
+
+int
+g_rename (const gchar *oldfilename,
+	  const gchar *newfilename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *woldfilename = g_utf8_to_utf16 (oldfilename, -1, NULL, NULL, NULL);
+      wchar_t *wnewfilename = g_utf8_to_utf16 (newfilename, -1, NULL, NULL, NULL);
+      int retval = _wrename (woldfilename, wnewfilename);
+      int save_errno = errno;
+      
+      g_free (woldfilename);
+      g_free (wnewfilename);
+      
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_oldfilename = g_locale_from_utf8 (oldfilename, -1, NULL, NULL, NULL);
+      gchar *cp_newfilename = g_locale_from_utf8 (newfilename, -1, NULL, NULL, NULL);
+      int retval = rename (cp_oldfilename, cp_newfilename);
+      int save_errno = errno;
+
+      g_free (cp_oldfilename);
+      g_free (cp_newfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return rename (oldfilename, newfilename);
+#endif
+}
+
+int
+g_mkdir (const gchar *filename,
+	 int          mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wmkdir (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = mkdir (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return mkdir (filename, mode);
+#endif
+}
+
+int
+g_stat (const gchar *filename,
+	struct stat *buf)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wstat (wfilename, (struct _stat *) buf);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = stat (cp_filename, buf);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return stat (filename, buf);
+#endif
+}
+
+int
+g_unlink (const gchar *filename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wunlink (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = unlink (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return unlink (filename);
+#endif
+}
+
+int
+g_remove (const gchar *filename)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      int retval = _wremove (wfilename);
+      int save_errno = errno;
+
+      g_free (wfilename);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      int retval = remove (cp_filename);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return remove (filename);
+#endif
+}
+
+FILE *
+g_fopen (const gchar *filename,
+	 const gchar *mode)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfopen (wfilename, wmode);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      g_free (wmode);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      FILE *retval = fopen (cp_filename, mode);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return fopen (filename, mode);
+#endif
+}
+
+FILE *
+g_freopen (const gchar *filename,
+	   const gchar *mode,
+	   FILE        *stream)
+{
+#ifdef G_OS_WIN32
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
+      wchar_t *wmode = g_utf8_to_utf16 (mode, -1, NULL, NULL, NULL);
+      FILE *retval = _wfreopen (wfilename, wmode, stream);
+      int save_errno = errno;
+
+      g_free (wfilename);
+      g_free (wmode);
+
+      errno = save_errno;
+      return retval;
+    }
+  else
+    {
+      gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL);
+      FILE *retval = freopen (cp_filename, mode, stream);
+      int save_errno = errno;
+
+      g_free (cp_filename);
+
+      errno = save_errno;
+      return retval;
+    }
+#else
+  return freopen (filename, mode, stream);
+#endif
+}
--- /dev/null	2004-08-24 23:18:58.441000000 +0000
+++ glib/gfilewrappers.h	2004-08-23 22:35:27.008670400 +0000
@@ -0,0 +1,56 @@
+/* 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. On
+ * Unix, the pathname is a file name as it literally is in the file
+ * system. On Windows, it's the file name in UTF-8.
+ */
+
+int g_open      (const gchar *filename,
+                 int          flags,
+                 int          mode);
+
+int g_rename    (const gchar *oldfilename,
+                 const gchar *newfilename);
+
+int g_mkdir     (const gchar *filename,
+                 int          mode);
+
+int g_stat      (const gchar *filename,
+                 struct stat *buf);
+
+int g_unlink    (const gchar *filename);
+
+int g_remove    (const gchar *filename);
+
+FILE *g_fopen   (const gchar *filename,
+                 const gchar *mode);
+
+FILE *g_freopen (const gchar *filename,
+                 const gchar *mode,
+                 FILE        *stream);
+
+#endif /* __G_FILEWRAPPERS_H__ */
