Index: glib/gdir.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.c,v
retrieving revision 1.12
diff -u -2 -r1.12 gdir.c
--- glib/gdir.c	27 Oct 2004 16:46:29 -0000	1.12
+++ glib/gdir.c	4 Nov 2004 03:01:03 -0000
@@ -26,5 +26,6 @@
 
 #include <errno.h>
-#include <string.h> /* strcmp */
+#include <string.h>
+#include <sys/stat.h>
 
 #ifdef HAVE_DIRENT_H
@@ -52,4 +53,121 @@
 };
 
+/* Must have these here before the #undef of g_dir_open and
+ * g_dir_read_name later in this file...
+ */
+
+static GFTWCallbackReturnStatus
+g_ftw_internal (gint        level,
+		const gchar *path,
+		gint        flags,
+		GFTWFunc    callback,
+		gpointer    user_data,
+		GError    **error,
+		gint       *counter)
+{
+  const gchar *entry;
+  GDir *dir = g_dir_open (path, 0, error);
+  GFTWCallbackReturnStatus callback_flag = G_FTW_CALLBACK_CONTINUE;
+
+  if (dir == NULL)
+    return (*callback) (level, path, G_FTW_ENTRY_DIR_OPEN_FAILED, NULL, user_data);
+
+  while ((entry = g_dir_read_name (dir)) != NULL)
+    {
+      gint stat_rc;
+      gchar *fullpath = g_strconcat (path, G_DIR_SEPARATOR_S, entry, NULL);
+#ifdef G_OS_WIN32
+      struct _stati64 st;
+
+      if (G_WIN32_HAVE_WIDECHAR_API ())
+	{
+	  wchar_t *wfullpath = g_utf8_to_utf16 (fullpath, -1, NULL, NULL, NULL);
+	  stat_rc = _wstati64 (wfullpath, &st);
+	  g_free (wfullpath);
+	}
+      else
+	{
+	  gchar *cp_fullpath = g_locale_from_utf8 (fullpath, -1, NULL, NULL, NULL);
+	  stat_rc = _stati64 (cp_fullpath, &st);
+	  g_free (cp_fullpath);
+	}
+      
+#else
+      struct stat st;
+      stat_rc = stat (fullpath, &st);
+#endif
+      if (stat_rc == -1)
+	(*callback) (level, fullpath, G_FTW_ENTRY_STAT_FAILED, NULL, user_data);
+      else
+	{
+	  GFTWEntryStatus status;
+
+	  status.st_size = st.st_size;
+	  status.st_mode = st.st_mode;
+	  status.st_nlink = st.st_nlink;
+	  status.st_uid = st.st_uid;
+	  status.st_gid = st.st_gid;
+	  status.st_mtime = st.st_mtime;
+	  status.st_atime = st.st_atime;
+	  status.st_ctime = st.st_ctime;
+
+	  (*counter)++;
+	  callback_flag = (*callback) (level, fullpath, G_FTW_ENTRY_OK,
+				       &status, user_data);
+	  if (callback_flag != G_FTW_CALLBACK_CONTINUE)
+	    {
+	      g_free (fullpath);
+	      break;
+	    }
+
+	  if (st.st_mode & S_IFDIR)
+	    {
+	      callback_flag = g_ftw_internal (level + 1, fullpath, flags,
+					      callback, user_data, error,
+					      counter);
+	      if (callback_flag != G_FTW_CALLBACK_CONTINUE)
+		{
+		  g_free (fullpath);
+		  break;
+		}
+	    }
+	}
+      g_free (fullpath);
+    }
+  g_dir_close (dir);
+
+  if (callback_flag == G_FTW_CALLBACK_BREAK_TO_TOP)
+    return G_FTW_CALLBACK_BREAK_TO_TOP;
+  else
+    return G_FTW_CALLBACK_CONTINUE;
+}
+
+/**
+ * g_file_tree_walk:
+ * @path: The path to the root of the directory tree, in the GLib file name encoding
+ * @flags: bitfield of #GFileTreeWalk flags
+ * @callback: A callback function to be called for each entry in the tree
+ * @user_data: Passed on to the callback funtion.
+ * @error: return location for a #GError, or %NULL.
+ *
+ * This function is implemented in GLib and does not use the C
+ * library's ftw() or nftw() functions even if present.
+ *
+ * Return value: Number of times the callback function was called with
+ * a non-NULL entry status parameter.
+ */
+gint
+g_file_tree_walk (const gchar  *path,
+		  gint          flags,
+		  GFTWFunc      callback,
+		  gpointer      user_data,
+		  GError      **error)
+{
+  gint count = 0;
+  g_ftw_internal (0, path, flags, callback, user_data, error, &count);
+
+  return count;
+}
+		  
 /**
  * g_dir_open:
@@ -344,2 +462,3 @@
   g_free (dir);
 }
+
Index: glib/gdir.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.h,v
retrieving revision 1.4
diff -u -2 -r1.4 gdir.h
--- glib/gdir.h	27 Oct 2004 16:46:29 -0000	1.4
+++ glib/gdir.h	4 Nov 2004 03:01:03 -0000
@@ -30,4 +30,41 @@
 typedef struct _GDir GDir;
 
+/* Can't use struct stat as that might be different inside GLib than
+ * in the calling program, because of large file support.
+ */
+typedef struct _GFTWEntryStatus GFTWEntryStatus;
+
+struct _GFTWEntryStatus
+{
+  guint64 st_size;
+  guint st_mode;
+  guint st_nlink; 
+  gint st_uid;
+  gint st_gid;
+  gulong st_mtime;
+  gulong st_atime;
+  gulong st_ctime;
+};
+
+typedef enum { G_FTW_FLAG_FOLLOW_SYMLINKS,
+	       G_FTW_FLAG_CROSS_MOUNTPOINTS
+} GFTWFlags;
+
+typedef enum { G_FTW_ENTRY_OK,
+	       G_FTW_ENTRY_STAT_FAILED,
+	       G_FTW_ENTRY_DIR_OPEN_FAILED
+} GFTWEntryFlags;
+
+typedef enum { G_FTW_CALLBACK_CONTINUE,
+	       G_FTW_CALLBACK_BREAK_THIS_LEVEL,
+	       G_FTW_CALLBACK_BREAK_TO_TOP
+} GFTWCallbackReturnStatus;
+
+typedef GFTWCallbackReturnStatus (*GFTWFunc) (gint             level,
+					      const gchar     *entry,
+					      gint             flags,
+					      GFTWEntryStatus *status,
+					      gpointer         user_data);
+
 #ifdef G_OS_WIN32
 /* For DLL ABI stability, keep old names for old (non-UTF-8) functionality. */
@@ -42,4 +79,10 @@
 void                     g_dir_rewind         (GDir         *dir);
 void                     g_dir_close          (GDir         *dir);
+
+int                      g_file_tree_walk     (const gchar  *path,
+					       gint          flags,
+					       GFTWFunc      callback,
+					       gpointer      user_data,
+					       GError      **error);
 
 G_END_DECLS
