Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/ChangeLog,v
retrieving revision 1.2347
diff -p -a -u -r1.2347 ChangeLog
--- ChangeLog	16 May 2006 05:46:34 -0000	1.2347
+++ ChangeLog	20 May 2006 17:20:59 -0000
@@ -1,3 +1,10 @@
+2005-05-21  Emmanuele Bassi  <ebassi@gnome.org>
+
+	* glib/gdir.h:
+	* glib/gdir.c: Add g_file_tree_walk(), a portable replacement
+	for ftw() and nftw() POSIX functions (#157076, original
+	patch by Tor Lillqvist)
+
 2006-05-16  Matthias Clasen  <mclasen@redhat.com>
 
 	* tests/Makefile.am: 
Index: docs/reference/ChangeLog
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/ChangeLog,v
retrieving revision 1.484
diff -p -a -u -r1.484 ChangeLog
--- docs/reference/ChangeLog	16 May 2006 05:49:46 -0000	1.484
+++ docs/reference/ChangeLog	20 May 2006 17:21:00 -0000
@@ -1,3 +1,7 @@
+2006-05-21  Emmanuele Bassi  <ebassi@gnome.org>
+
+	* glib/glib-sections.txt: Add g_file_tree_walk
+
 2006-05-16  Matthias Clasen  <mclasen@redhat.com>
 
 	* glib/glib-sections.txt: Add g_ascii_strtoll
Index: docs/reference/glib/glib-sections.txt
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/glib-sections.txt,v
retrieving revision 1.147
diff -p -a -u -r1.147 glib-sections.txt
--- docs/reference/glib/glib-sections.txt	16 May 2006 05:49:46 -0000	1.147
+++ docs/reference/glib/glib-sections.txt	20 May 2006 17:21:00 -0000
@@ -1012,6 +1012,7 @@ g_dir_open
 g_dir_read_name
 g_dir_rewind
 g_dir_close
+g_file_tree_walk
 
 <SUBSECTION>
 GMappedFile
Index: glib/gdir.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.c,v
retrieving revision 1.14
diff -p -a -u -r1.14 gdir.c
--- glib/gdir.c	14 Mar 2005 04:26:57 -0000	1.14
+++ glib/gdir.c	20 May 2006 17:21:00 -0000
@@ -25,7 +25,8 @@
 #include "config.h"
 
 #include <errno.h>
-#include <string.h> /* strcmp */
+#include <string.h>
+#include <sys/stat.h>
 
 #ifdef HAVE_DIRENT_H
 #include <sys/types.h>
@@ -52,6 +53,138 @@ struct _GDir
 #endif
 };
 
+/* 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)
+{
+  GFTWCallbackReturnStatus callback_flag = G_FTW_CALLBACK_CONTINUE;
+  gint stat_rc;
+#ifdef G_OS_WIN32
+  struct _stati64 st;
+
+  if (G_WIN32_HAVE_WIDECHAR_API ())
+    {
+      wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
+      stat_rc = _wstati64 (wpath, &st);
+      g_free (wpath);
+    }
+  else
+    {
+      gchar *cp_path = g_locale_from_utf8 (path, -1, NULL, NULL, NULL);
+      stat_rc = _stati64 (cp_path, &st);
+      g_free (cp_path);
+    }
+#else
+  struct stat st;
+  stat_rc = stat (path, &st);
+#endif
+
+  if (stat_rc == -1)
+    (*callback) (level, path, G_FTW_ENTRY_STAT_FAILED, NULL, user_data);
+  else
+    {
+      GFTWEntryStatus status;
+
+#ifndef G_OS_WIN32
+      if ((st.st_mode & S_IFLNK) &&
+	  !(flags & G_FTW_FLAG_FOLLOW_SYMLINKS))
+        {
+          stat_rc = lstat (path, &st);
+	  if (stat_rc == -1)
+            (*callback) (level, path, G_FTW_ENTRY_STAT_FAILED, NULL, user_data);
+	}
+#endif /* !G_OS_WIN32 */
+
+      status.size = st.st_size;
+      status.mode = st.st_mode;
+      status.nlink = st.st_nlink;
+      status.uid = st.st_uid;
+      status.gid = st.st_gid;
+      status.mtime = st.st_mtime;
+      status.atime = st.st_atime;
+      status.ctime = st.st_ctime;
+      
+      (*callback) (level, path, G_FTW_ENTRY_OK, &status, user_data);
+      (*counter)++;
+
+      if (st.st_mode & S_IFDIR)
+	{
+	  const gchar *entry;
+	  GDir *dir = g_dir_open (path, 0, error);
+      
+	  if (dir == NULL)
+	    return (*callback) (level, path, G_FTW_ENTRY_DIR_OPEN_FAILED, NULL, user_data);
+
+	  while ((entry = g_dir_read_name (dir)) != NULL)
+	    {
+	      gchar *fullpath = g_build_filename (path, entry, NULL);
+
+	      callback_flag = g_ftw_internal (level + 1, fullpath,
+					      flags, callback, user_data,
+					      error, counter);
+
+	      g_free (fullpath);
+
+	      if (callback_flag != G_FTW_CALLBACK_CONTINUE)
+		break;
+	    }
+	  
+	  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 a file or directory in the GLib file name encoding
+ * @flags: bitfield of #GFileTreeWalk flags
+ * @callback: A callback function to be called for each entry in the tree
+ *   rooted at @path.
+ * @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 those would be
+ * available.
+ *
+ * The file system subtree rooted at @path is walked in preorder
+ * (i.e., directories are visited before their entries) and for each
+ * file or directory in the tree, @callback is called. @callback is
+ * also called if for some reason the attributes of a file could not
+ * be determined, or if a directory could not be traversed. Typically
+ * @path is a directory. If @path is a file, obviously the tree is
+ * just that one file, and @callback will be called just once.
+ *
+ * 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:
  * @path: the path to the directory you are interested in. On Unix
@@ -344,6 +477,7 @@ g_dir_close (GDir *dir)
   closedir (dir->u.dirp);
   g_free (dir);
 }
+
 
 #define __G_DIR_C__
 #include "galiasdef.c"
Index: glib/gdir.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gdir.h,v
retrieving revision 1.4
diff -p -a -u -r1.4 gdir.h
--- glib/gdir.h	27 Oct 2004 16:46:29 -0000	1.4
+++ glib/gdir.h	20 May 2006 17:21:00 -0000
@@ -29,6 +29,46 @@ G_BEGIN_DECLS
 
 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 size;
+  guint mode;
+  guint nlink;
+  gint uid;
+  gint gid;
+  gulong mtime;
+  gulong atime;
+  gulong 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. */
 #define g_dir_open g_dir_open_utf8
@@ -41,6 +81,12 @@ GDir    *                g_dir_open     
 G_CONST_RETURN gchar    *g_dir_read_name      (GDir         *dir);
 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
 
Index: glib/glib.symbols
===================================================================
RCS file: /cvs/gnome/glib/glib/glib.symbols,v
retrieving revision 1.65
diff -p -a -u -r1.65 glib.symbols
--- glib/glib.symbols	16 May 2006 05:46:36 -0000	1.65
+++ glib/glib.symbols	20 May 2006 17:21:00 -0000
@@ -307,6 +307,7 @@ g_dir_open_utf8
 g_dir_read_name_utf8
 #endif
 g_dir_rewind
+g_file_tree_walk
 #endif
 #endif
 
