Index: thunar-vfs-deep-count-job.c =================================================================== --- thunar-vfs-deep-count-job.c (revision 20534) +++ thunar-vfs-deep-count-job.c (working copy) @@ -53,16 +53,21 @@ -static void thunar_vfs_deep_count_job_class_init (ThunarVfsJobClass *klass); -static void thunar_vfs_deep_count_job_finalize (GObject *object); -static void thunar_vfs_deep_count_job_execute (ThunarVfsJob *job); -static gboolean thunar_vfs_deep_count_job_process (ThunarVfsDeepCountJob *deep_count_job, - const gchar *dir_path, - struct stat *statb); -static void thunar_vfs_deep_count_job_status_ready (ThunarVfsDeepCountJob *deep_count_job); +typedef struct _ThunarVfsDeepCountInode ThunarVfsDeepCountInode; +static void thunar_vfs_deep_count_job_class_init (ThunarVfsJobClass *klass); +static void thunar_vfs_deep_count_job_finalize (GObject *object); +static void thunar_vfs_deep_count_job_execute (ThunarVfsJob *job); +static gboolean thunar_vfs_deep_count_job_process (ThunarVfsDeepCountJob *deep_count_job, + const gchar *dir_path, + struct stat *statb, + ThunarVfsDeepCountInode *inodes); +static void thunar_vfs_deep_count_job_status_ready (ThunarVfsDeepCountJob *deep_count_job); + + + struct _ThunarVfsDeepCountJobClass { ThunarVfsJobClass __parent__; @@ -90,8 +95,15 @@ guint unreadable_directory_count; }; +struct _ThunarVfsDeepCountInode +{ + /* helper struct to avoid endless recursion on symlinks */ + ThunarVfsDeepCountInode *parent; + ino_t inode; +}; + static GObjectClass *thunar_vfs_deep_count_job_parent_class; static guint deep_count_signals[LAST_SIGNAL]; @@ -205,7 +217,7 @@ else { /* process the directory recursively */ - if (thunar_vfs_deep_count_job_process (deep_count_job, absolute_path, &statb)) + if (thunar_vfs_deep_count_job_process (deep_count_job, absolute_path, &statb, NULL)) { /* emit "status-ready" signal */ thunar_vfs_job_emit (THUNAR_VFS_JOB (deep_count_job), deep_count_signals[STATUS_READY], @@ -228,13 +240,16 @@ static gboolean -thunar_vfs_deep_count_job_process (ThunarVfsDeepCountJob *deep_count_job, - const gchar *dir_path, - struct stat *statb) +thunar_vfs_deep_count_job_process (ThunarVfsDeepCountJob *deep_count_job, + const gchar *dir_path, + struct stat *statb, + ThunarVfsDeepCountInode *inodes) { - const gchar *name; - gchar *path; - GDir *dp; + ThunarVfsDeepCountInode *ip; + ThunarVfsDeepCountInode inode; + const gchar *name; + gchar *path; + GDir *dp; /* try to open the directory */ dp = g_dir_open (dir_path, 0, NULL); @@ -267,16 +282,34 @@ /* check if we have a directory here */ if (S_ISDIR (statb->st_mode)) { - /* process the directory recursively */ - if (thunar_vfs_deep_count_job_process (deep_count_job, path, statb)) + /* check if we already have that inode (avoid recursion on symlinks) */ + for (ip = inodes; ip != NULL; ip = ip->parent) + if (ip->inode == statb->st_ino) + break; + + /* check if we'd recurse */ + if (G_UNLIKELY (ip != NULL)) { - /* directory was readable */ - deep_count_job->directory_count += 1; + /* revert the total size change */ + deep_count_job->total_size -= statb->st_size; } else { - /* directory was unreadable */ - deep_count_job->unreadable_directory_count += 1; + /* avoid recursion */ + inode.parent = inodes; + inode.inode = statb->st_ino; + + /* process the directory recursively */ + if (thunar_vfs_deep_count_job_process (deep_count_job, path, statb, &inode)) + { + /* directory was readable */ + deep_count_job->directory_count += 1; + } + else + { + /* directory was unreadable */ + deep_count_job->unreadable_directory_count += 1; + } } } else