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