1 /* gtkdirtree - gtkdirtree widget for gtk+
2  * Copyright 1999-2001  Adrian E. Feiguin <feiguin@ifir.edu.ar>
3  *
4  * check_dir - taken from gtk+ (gtkfilesel.c)
5  * Copyright (C) 2001 Chris Kuklewicz <chrisk at mit.edu>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
23 /**
24  * SECTION: gtkdirtree
25  * @short_description: A directory tree widget for GTK.
26  *
27  * It is a GtkCTree subclass that allows you to navigate the file-system.
28  */
29 
30 /**
31  * GtkDirTree:
32  *
33  * The GtkDirTree struct contains only private data.
34  * It should only be accessed through the functions described below.
35  */
36 
37 
38 #include "config.h"
39 #include <gtk/gtk.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 
51 #ifdef HAVE_DIRENT_H
52 #include <dirent.h>
53 #endif
54 
55 #ifdef G_OS_WIN32
56 #define STRICT
57 #include <windows.h> /* GetLogicalDriveStrings */
58 
59 #ifndef S_ISDIR
60 #define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
61 #define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
62 #define S_ISLNK(m) (0)
63 #elif defined(_WIN32)
64 #define S_ISLNK(m) (0)
65 #endif
66 #endif
67 
68 #include <string.h>
69 #include "gtkdirtree.h"
70 
71 #ifndef MAXHOSTNAMELEN
72 #define MAXHOSTNAMELEN 64
73 #endif
74 
75 #ifndef MAXPATHLEN
76 #define MAXPATHLEN 1024
77 #endif
78 
79 static void destroy_tree(gpointer data);
80 static void expand_tree(GtkCTree *ctree,GtkCTreeNode *parent_node, gpointer data);
81 static gboolean accept_dirname (char *dirname, gboolean show_hidden);
82 gboolean check_dir_extra (gchar *dir_name, struct stat *result, gboolean *stat_subdirs);
83 
84 /* XPM */
85 static char * dennied_xpm[] = {
86 "16 16 9 1",
87 " 	c None",
88 ".	c #000000",
89 "X	c #EFE8EF",
90 "o	c #FFF8CF",
91 "O	c #FFF890",
92 "+	c #CFC860",
93 "@	c #FF0000",
94 "#	c #FFC890",
95 "x	c #909000",
96 "                ",
97 "  xxxxx.        ",
98 " xXooOO .       ",
99 "x++++@@@@xxxx   ",
100 "xoo@@@@@@@@oO+. ",
101 "xoO@@OOOO@@O#+. ",
102 "xo@@OOOO@@@@O+. ",
103 "xo@@OOO@@O@@#+. ",
104 "xo@@OO@@O#@@O+. ",
105 "xo@@O@@O#O@@#+. ",
106 "xo@@@@O#O#@@#+. ",
107 "xo#@@O#O#@@##+. ",
108 "x++@@@@@@@@+++. ",
109 " ....@@@@...... ",
110 "                ",
111 "                "};
112 
113 static char * folder_xpm[] = {
114 "16 16 8 1",
115 " 	c None",
116 ".	c #909000",
117 "+	c #000000",
118 "@	c #EFE8EF",
119 "#	c #FFF8CF",
120 "$	c #FFF890",
121 "%	c #CFC860",
122 "&	c #FFC890",
123 "                ",
124 "  .....+        ",
125 " .@##$$.+       ",
126 ".%%%%%%%......  ",
127 ".###########$%+ ",
128 ".#$$$$$$$$$$&%+ ",
129 ".#$$$$$$$&$&$%+ ",
130 ".#$$$$$$$$&$&%+ ",
131 ".#$$$$$&$&$&$%+ ",
132 ".#$$$$$$&$&$&%+ ",
133 ".#$$$&$&$&$&&%+ ",
134 ".#&$&$&$&$&&&%+ ",
135 ".%%%%%%%%%%%%%+ ",
136 " ++++++++++++++ ",
137 "                ",
138 "                "};
139 
140 /* XPM */
141 static char * ofolder_xpm[] = {
142 "16 16 12 1",
143 " 	c None",
144 ".	c #808080",
145 "+	c #E0E0D0",
146 "@	c #4F484F",
147 "#	c #909000",
148 "$	c #FFF8EF",
149 "%	c #CFC860",
150 "&	c #003090",
151 "*	c #7F7800",
152 "=	c #FFC890",
153 "-	c #FFF890",
154 ";	c #2F3000",
155 "        .       ",
156 "       .+@      ",
157 "   ###.$$+@     ",
158 "  #%%.$$$$+@    ",
159 "  #%.$$$&$$+@** ",
160 "  #.+++&+&+++@* ",
161 "############++@ ",
162 "#$$$$$$$$$=%#++@",
163 "#$-------=-=#+; ",
164 " #---=--=-==%#; ",
165 " #-----=-=-==#; ",
166 " #-=--=-=-=-=#; ",
167 "  #=-=-=-=-==#; ",
168 "  ############; ",
169 "   ;;;;;;;;;;;  ",
170 "                "};
171 
172 
173 
174 /* XPM */
175 static char * mypc_xpm[] = {
176 "18 18 7 1",
177 " 	c None",
178 ".	c #808080",
179 "+	c #C0C0C0",
180 "@	c #000000",
181 "#	c #FFFFFF",
182 "$	c #0000FF",
183 "%	c #FFFF00",
184 "                  ",
185 "                  ",
186 "                  ",
187 "     .........    ",
188 "    .++++++++.@   ",
189 "   .########..@   ",
190 "   .#$$$$$$#..@   ",
191 "   .#$%$$$$#..@   ",
192 "   .#$$$$$$#..@   ",
193 "   .#$$$$$$#..@   ",
194 "   .########.@.   ",
195 "   .@@@@@@@@@.+@  ",
196 "  .#########.+.@  ",
197 "  ..@.@.@.@.@..@  ",
198 " .+@+@+@+@+@+@@   ",
199 ".###########+@    ",
200 "@@@@@@@@@@@@@     ",
201 "                  "};
202 
203 
204 static void gtk_dir_tree_class_init          (GtkDirTreeClass *klass);
205 static void gtk_dir_tree_init                (GtkDirTree      *dir_tree);
206 
207 
208 static GtkCTreeClass *parent_class = NULL;
209 
210 
211 GType
gtk_dir_tree_get_type(void)212 gtk_dir_tree_get_type (void)
213 {
214   static GType dir_tree_type = 0;
215 
216   if (!dir_tree_type)
217     {
218       dir_tree_type = g_type_register_static_simple (
219 		gtk_ctree_get_type(),
220 		"GtkDirTree",
221 		sizeof (GtkDirTreeClass),
222 		(GClassInitFunc) gtk_dir_tree_class_init,
223 		sizeof (GtkDirTree),
224 		(GInstanceInitFunc) gtk_dir_tree_init,
225 		0);
226 
227     }
228 
229   return dir_tree_type;
230 }
231 
232 GtkWidget*
gtk_dir_tree_new(void)233 gtk_dir_tree_new (void)
234 {
235   GtkWidget *widget;
236 
237   widget = gtk_widget_new (gtk_dir_tree_get_type(), NULL);
238 
239   return widget;
240 }
241 
242 static void
gtk_dir_tree_class_init(GtkDirTreeClass * klass)243 gtk_dir_tree_class_init (GtkDirTreeClass *klass)
244 {
245   GtkWidgetClass *widget_class;
246   GtkObjectClass *object_class;
247 
248   parent_class = g_type_class_ref (gtk_ctree_get_type ());
249   widget_class = (GtkWidgetClass*) klass;
250   object_class = (GtkObjectClass *) klass;
251 
252 }
253 
254 static void
gtk_dir_tree_init(GtkDirTree * dir_tree)255 gtk_dir_tree_init (GtkDirTree *dir_tree)
256 {
257   GtkCTreeNode *root_node,*mypc_node,*node;
258   GtkDirTreeNode *dirnode;
259   gchar *root_text=G_DIR_SEPARATOR_S,*node_text="dummy";
260   gchar localhost[MAXHOSTNAMELEN];
261   GtkWidget *widget;
262   GdkColormap *colormap;
263 #ifdef G_OS_WIN32
264   gchar  drives[128];
265   gchar* drive;
266 #endif
267 
268   widget = GTK_WIDGET(dir_tree);
269   colormap = gdk_colormap_get_system();
270 
271   dir_tree->show_hidden = TRUE;
272 
273   /* Get the local hostname. */
274 #ifndef G_OS_WIN32
275   if ((gethostname (localhost, MAXHOSTNAMELEN) != 0) &&
276       (getdomainname (localhost, MAXHOSTNAMELEN) != 0))
277     strcpy (localhost, "LocalHost");
278 #else
279     strcpy (localhost, "My PC");
280 #endif
281 
282   dir_tree->local_hostname = g_strdup(localhost);
283   g_object_set(G_OBJECT(widget), "n_columns", 1, "tree_column", 0, NULL);
284 
285 
286   gtk_clist_set_row_height (GTK_CLIST (dir_tree), 18);
287 
288   dir_tree->my_pc=gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap,
289                                                        &dir_tree->my_pc_mask,
290                                                        NULL,mypc_xpm);
291   dir_tree->folder=gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap,
292                                                        &dir_tree->folder_mask,
293                                                        NULL,folder_xpm);
294   dir_tree->ofolder=gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap,
295                                                         &dir_tree->ofolder_mask,
296                                                         NULL,ofolder_xpm);
297   dir_tree->dennied=gdk_pixmap_colormap_create_from_xpm_d(NULL, colormap,
298                                                         &dir_tree->dennied_mask,
299                                                         NULL,dennied_xpm);
300 
301   gtk_clist_set_column_auto_resize(GTK_CLIST(dir_tree),0,TRUE);
302   gtk_clist_set_selection_mode(GTK_CLIST(dir_tree),GTK_SELECTION_SINGLE);
303   gtk_ctree_set_line_style(GTK_CTREE(dir_tree),GTK_CTREE_LINES_DOTTED);
304 
305   g_signal_connect(GTK_OBJECT(dir_tree),"tree_expand",G_CALLBACK(expand_tree), NULL);
306 
307   mypc_node=gtk_ctree_insert_node(GTK_CTREE(dir_tree),NULL,NULL,&dir_tree->local_hostname,4,dir_tree->my_pc,dir_tree->my_pc_mask,dir_tree->my_pc,dir_tree->my_pc_mask,FALSE,FALSE);
308 
309   dirnode=g_malloc0(sizeof(GtkDirTreeNode));
310   dirnode->path = dir_tree->local_hostname;
311   gtk_ctree_node_set_row_data_full(GTK_CTREE(dir_tree),mypc_node,dirnode,destroy_tree);
312 
313 #ifndef G_OS_WIN32
314   root_node=gtk_ctree_insert_node(GTK_CTREE(dir_tree),mypc_node,NULL,&root_text,4,dir_tree->folder,dir_tree->folder_mask,dir_tree->ofolder,dir_tree->ofolder_mask,FALSE,FALSE);
315 
316   dirnode=g_malloc0(sizeof(GtkDirTreeNode));
317   dirnode->path=g_strdup(G_DIR_SEPARATOR_S);
318   gtk_ctree_node_set_row_data_full(GTK_CTREE(dir_tree),root_node,dirnode,destroy_tree);
319   node=gtk_ctree_insert_node(GTK_CTREE(dir_tree),root_node,NULL,&node_text,4,NULL,NULL,NULL,NULL,TRUE,TRUE);
320   gtk_ctree_expand(GTK_CTREE(dir_tree),mypc_node);
321 
322   gtk_ctree_select(GTK_CTREE(dir_tree),root_node);
323 #else
324   /* On Windoze there isn't one unique root directory "/" but instead
325    * there are logical drives a:, c: ... . Insert them into the dir_tree.
326    */
327 
328   /* Get the Drives string */
329   GetLogicalDriveStrings(sizeof(drives), drives);
330   drive = drives;
331   /* add an entry for every existing drive */
332   while (*drive != '\0')
333   {
334     root_node=gtk_ctree_insert_node(GTK_CTREE(dir_tree),mypc_node,NULL,&drive,4,dir_tree->folder,dir_tree->folder_mask,dir_tree->ofolder,dir_tree->ofolder_mask,FALSE,FALSE);
335 
336     dirnode = g_malloc0(sizeof(GtkDirTreeNode));
337     dirnode->path = g_strdup(drive);
338     gtk_ctree_node_set_row_data_full(GTK_CTREE(dir_tree),root_node,dirnode,destroy_tree);
339     node=gtk_ctree_insert_node(GTK_CTREE(dir_tree),root_node,NULL,&node_text, 4,NULL,NULL,NULL,NULL,TRUE,TRUE);
340     drive += (strlen(drive) + 1);
341   }
342 
343   gtk_ctree_expand(GTK_CTREE(dir_tree),mypc_node);
344   gtk_ctree_select(GTK_CTREE(dir_tree),mypc_node);
345 #endif
346 
347 }
348 
accept_dirname(char * dirname,gboolean show_hidden)349 static gboolean accept_dirname (char *dirname, gboolean show_hidden)
350 {
351     if(dirname[0]!='.') return TRUE;
352     if (show_hidden)
353 	if (strcmp(dirname, ".") && strcmp(dirname, ".."))
354 	    return TRUE;
355     return FALSE;
356 }
357 
check_for_subdir(gchar * path,gboolean show_hidden)358 static gboolean check_for_subdir(gchar *path, gboolean show_hidden)
359 {
360   DIR *dir;
361   struct dirent *dirent;
362   struct stat statbuf;
363   gchar *npath;
364 
365   if((dir=opendir(path))!=NULL)
366   {
367     while((dirent=readdir(dir))!=NULL)
368     {
369 	if(accept_dirname(dirent->d_name,show_hidden))
370       {
371 #ifndef G_OS_WIN32
372         npath=g_strconcat(path,dirent->d_name,G_DIR_SEPARATOR_S,NULL);
373 #else
374         /* the M$ stat is somewhat pedantic ... */
375         npath=g_strconcat(path,dirent->d_name,NULL);
376 #endif
377         if(0!=stat(npath,&statbuf))
378         {
379           g_free(npath);
380           continue;
381         }
382         g_free(npath);
383         if(S_ISDIR(statbuf.st_mode))
384         {
385           closedir(dir);
386           return TRUE;
387         }
388       }
389     }
390     closedir(dir);
391   }
392 /*
393   else
394     g_warning("check_for_subdir: opendir(%s) failed", path);
395 */
396 
397   return FALSE;
398 }
399 
400 static void
destroy_tree(gpointer data)401 destroy_tree(gpointer data)
402 {
403 
404   GtkDirTreeNode *node;
405   node = data;
406   g_free(node->path);
407   g_free(node);
408 }
409 
410 static void
expand_tree(GtkCTree * ctree,GtkCTreeNode * parent_node,gpointer data)411 expand_tree(GtkCTree *ctree,GtkCTreeNode *parent_node, gpointer data)
412 {
413   DIR *dir;
414   struct dirent *dirent;
415   gchar *path,*text,*dummy="dummy";
416   struct stat statbuf;
417   GtkCTreeNode *node,*sub_node;
418   GtkDirTreeNode *parent_dirnode,*dirnode;
419   gboolean has_subdir=FALSE;
420   gboolean show_hidden;
421   gboolean stat_subdirs=TRUE;
422   gboolean can_open_subdir;
423   GtkDirTree *dir_tree;
424   GtkWidget *widget;
425 
426   widget = GTK_WIDGET(ctree);
427   dir_tree = GTK_DIR_TREE(widget);
428   show_hidden = dir_tree->show_hidden;
429 
430   parent_dirnode=gtk_ctree_node_get_row_data(GTK_CTREE(widget),parent_node);
431 
432   if(parent_dirnode->path == dir_tree->local_hostname) return;
433 
434   if(!parent_dirnode->scanned)
435   {
436     gtk_clist_freeze(GTK_CLIST(widget));
437     node=gtk_ctree_find_by_row_data(GTK_CTREE(widget),parent_node,NULL);
438     gtk_ctree_remove_node(GTK_CTREE(widget),node);
439     if((dir=opendir(parent_dirnode->path))!=NULL)
440     {
441       if(!check_dir_extra(parent_dirnode->path,&statbuf,&stat_subdirs))
442       {
443         closedir(dir);
444         gtk_clist_thaw(GTK_CLIST(widget));
445         return;
446       }
447       while((dirent=readdir(dir))!=NULL)
448       {
449         path=g_strconcat(parent_dirnode->path,dirent->d_name,NULL);
450         if (stat_subdirs)
451         {
452           if(0!=stat(path,&statbuf))
453           {
454             g_free(path);
455             continue;
456           }
457         }
458         if(((!stat_subdirs)&&accept_dirname(dirent->d_name,show_hidden)) ||
459            (S_ISDIR(statbuf.st_mode)&&accept_dirname(dirent->d_name,show_hidden)))
460         {
461           DIR *dir_sub;
462           dirnode=g_malloc0(sizeof(GtkDirTreeNode));
463           dirnode->path=g_strconcat(path,G_DIR_SEPARATOR_S,NULL);
464           text=dirent->d_name;
465           if (stat_subdirs)
466           {
467             if(check_for_subdir(dirnode->path,show_hidden))
468                has_subdir=TRUE;
469             else
470                has_subdir=FALSE;
471             dir_sub = opendir(dirnode->path);
472             if( dir_sub != NULL )
473             {
474               closedir(dir_sub);
475               can_open_subdir=TRUE;
476             }
477             else
478             {
479               can_open_subdir=FALSE;
480             }
481           }
482           else
483           {
484             has_subdir=TRUE;
485             can_open_subdir=TRUE;
486           }
487 
488           if(can_open_subdir)
489           {
490              node=gtk_ctree_insert_node(GTK_CTREE(widget),parent_node,NULL,&text,4,dir_tree->folder,dir_tree->folder_mask,dir_tree->ofolder,dir_tree->ofolder_mask,!has_subdir,FALSE);
491           }
492           else
493           {
494              node=gtk_ctree_insert_node(GTK_CTREE(widget),parent_node,NULL,&text,4,dir_tree->dennied,dir_tree->dennied_mask,dir_tree->dennied,dir_tree->dennied_mask,!has_subdir,FALSE);
495           }
496 
497           gtk_ctree_node_set_row_data_full(GTK_CTREE(widget),node,dirnode,destroy_tree);
498           if(has_subdir)
499                   sub_node=gtk_ctree_insert_node(GTK_CTREE(widget),node,NULL,&dummy,4,NULL,NULL,NULL,NULL,FALSE,FALSE);
500         }
501         g_free(path);
502       }
503       closedir(dir);
504       gtk_ctree_sort_node(GTK_CTREE(widget),parent_node);
505     }
506     gtk_clist_thaw(GTK_CLIST(widget));
507     parent_dirnode->scanned=TRUE;
508   }
509 }
510 
511 /**
512  * gtk_dir_tree_open_dir:
513  * @dir_tree: #GtkDirTree widget.
514  * @path: #gchar path to the dir to be opened.
515  *
516  * Open files from directory path in dir_tree widget.
517  *
518  * Returns: TRUE(succes) or FALSE(failure).
519  */
520 
521 gint
gtk_dir_tree_open_dir(GtkDirTree * dir_tree,const gchar * path)522 gtk_dir_tree_open_dir(GtkDirTree *dir_tree, const gchar *path)
523 {
524   GtkCTreeNode *root_node, *node;
525   GtkDirTreeNode *dir_node;
526   DIR *dir;
527   gchar *c;
528   gchar *folder;
529   gint nlen;
530   gint new_path, new_node;
531   gchar *text;
532   gchar root[5], root1[5], root2[5], root3[5], root4[5];
533   gchar *aux_path = NULL, *real_path = NULL;
534 
535   if((dir=opendir(path)) == NULL) return FALSE;
536   closedir(dir);
537 
538   /* GET ABSOLUTE PATH */
539 
540   sprintf(root,"%s",G_DIR_SEPARATOR_S);
541   sprintf(root1,"%s.",G_DIR_SEPARATOR_S);
542   sprintf(root2,"%s..",G_DIR_SEPARATOR_S);
543   sprintf(root3,"%s..%s",G_DIR_SEPARATOR_S,G_DIR_SEPARATOR_S);
544   sprintf(root4,"%s.%s",G_DIR_SEPARATOR_S,G_DIR_SEPARATOR_S);
545 
546   if(path){
547      gint length;
548 
549      aux_path = g_strdup(path);
550      length = strlen(aux_path);
551 
552      if(strcmp(aux_path + length - 2, root1) == 0){
553         if(length == 2) {
554            g_free(aux_path);
555            aux_path = g_strdup(root);
556         } else {
557            aux_path[length - 1] = '\0';
558         }
559      } else if(strcmp(aux_path + length - 3, root2) == 0){
560         if(length == 3) {
561            g_free(aux_path);
562            aux_path = g_strdup(root);
563         } else {
564            gint i = length - 4;
565            while(i >= 0){
566               if(aux_path[i] == root[0]){
567                    aux_path[i+1] = '\0';
568                    break;
569               }
570               i--;
571            }
572         }
573      } else if(strcmp(aux_path + length - 4, root3) == 0){
574         if(length == 4) {
575            g_free(aux_path);
576            aux_path = g_strdup(root);
577         } else {
578            gint i = length - 5;
579            while(i >= 0){
580               if(aux_path[i] == root[0]){
581                    aux_path[i+1] = '\0';
582                    break;
583               }
584               i--;
585            }
586         }
587      } else if(strcmp(aux_path + length - 3, root4) == 0){
588         if(length == 3) {
589            g_free(aux_path);
590            aux_path = g_strdup(root);
591         } else {
592            aux_path[length - 2] = '\0';
593         }
594      }
595   }
596 
597   if(strlen(aux_path) == 0)
598     real_path = g_strdup(G_DIR_SEPARATOR_S);
599   else
600     real_path = g_strconcat(aux_path,G_DIR_SEPARATOR_S,NULL);
601 
602   g_free(aux_path);
603 
604   c = (gchar *)real_path;
605   folder = NULL;
606   nlen = 0;
607 
608   root_node = gtk_ctree_node_nth(GTK_CTREE(dir_tree), 1);
609   gtk_ctree_expand(GTK_CTREE(dir_tree), root_node);
610 
611   new_path = FALSE;
612   new_node = TRUE;
613 
614   while(*c != '\0' && *c != '\n' && c != NULL){
615    nlen++;
616    folder = (char *)g_realloc(folder, (nlen+1)*sizeof(char));
617    folder[nlen-1] = *c;
618    folder[nlen]='\0';
619    if(*c == G_DIR_SEPARATOR){
620        if(new_path){
621          node = GTK_CTREE_ROW(root_node)->children;
622          while(node){
623            dir_node = gtk_ctree_node_get_row_data(GTK_CTREE(dir_tree), node);
624            text = dir_node->path;
625            if(strcmp(text, folder) == 0){
626                 gtk_ctree_expand(GTK_CTREE(dir_tree), node);
627                 root_node = node;
628                 break;
629            }
630            node = GTK_CTREE_NODE_NEXT(node);
631          }
632        }
633        else
634        {
635          new_path = TRUE;
636        }
637        new_node = FALSE;
638    } else {
639        new_node = TRUE;
640    }
641    c++;
642   }
643 
644   if(new_node){
645      nlen++;
646      folder = (char *)g_realloc(folder, (nlen+1)*sizeof(char));
647      folder[nlen-1] = G_DIR_SEPARATOR;
648      folder[nlen]='\0';
649      node = GTK_CTREE_ROW(root_node)->children;
650      while(node){
651        dir_node = gtk_ctree_node_get_row_data(GTK_CTREE(dir_tree), node);
652        text = dir_node->path;
653        if(strcmp(text, folder) == 0){
654             gtk_ctree_expand(GTK_CTREE(dir_tree), node);
655             root_node = node;
656             break;
657        }
658        node = GTK_CTREE_NODE_NEXT(node);
659      }
660   }
661 
662   g_free(folder);
663   if (gtk_ctree_node_is_visible(GTK_CTREE(dir_tree), root_node) !=
664     GTK_VISIBILITY_FULL) {
665     gtk_widget_map(GTK_WIDGET(dir_tree));
666     gtk_ctree_node_moveto(GTK_CTREE(dir_tree), root_node, 0, 0.5, 0.5);
667   }
668   gtk_ctree_select(GTK_CTREE(dir_tree), root_node);
669 
670   g_free(real_path);
671   return TRUE;
672 }
673 
674 gboolean
check_dir_extra(gchar * dir_name,struct stat * result,gboolean * stat_subdirs)675 check_dir_extra (gchar *dir_name, struct stat *result, gboolean *stat_subdirs)
676 {
677   /* A list of directories that we know only contain other directories.
678    * Trying to stat every file in these directories would be very
679    * expensive.
680    */
681 
682   static struct {
683     gchar *name;
684     gboolean present;
685     struct stat statbuf;
686   } no_stat_dirs[] = {
687     { "/afs", FALSE, { 0 } },
688     { "/net", FALSE, { 0 } }
689   };
690 
691   static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]);
692   static gboolean initialized = FALSE;
693 
694   gint i;
695 
696   if (!initialized)
697     {
698       initialized = TRUE;
699       for (i = 0; i < n_no_stat_dirs; i++)
700         {
701           if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0)
702             no_stat_dirs[i].present = TRUE;
703         }
704     }
705 
706   if(stat(dir_name, result) < 0)
707     {
708 /*      cmpl_errno = errno;*/
709       return FALSE;
710     }
711 
712   *stat_subdirs = TRUE;
713   for (i=0; i<n_no_stat_dirs; i++)
714     {
715       if (no_stat_dirs[i].present &&
716           (no_stat_dirs[i].statbuf.st_dev == result->st_dev) &&
717           (no_stat_dirs[i].statbuf.st_ino == result->st_ino))
718         {
719           *stat_subdirs = FALSE;
720           break;
721         }
722     }
723 
724   return TRUE;
725 }
726 
727 
728