r3597: Bugfix: When opening a new directory with saved settings, the filer would
[rox-filer.git] / ROX-Filer / src / dir.c
blobd453370e71420fa884ddced98d5b27aa057abef0
1 /*
2 * $Id$
4 * Copyright (C) 2003, the ROX-Filer team.
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
21 /* dir.c - directory scanning and caching */
23 /* How it works:
25 * A Directory contains a list DirItems, each having a name and some details
26 * (size, image, owner, etc).
28 * There is a list of file names that need to be rechecked. While this
29 * list is non-empty, items are taken from the list in an idle callback
30 * and checked. Missing items are removed from the Directory, new items are
31 * added and existing items are updated if they've changed.
33 * When a whole directory is to be rescanned:
35 * - A list of all filenames in the directory is fetched, without any
36 * of the extra details.
37 * - This list is compared to the current DirItems, removing any that are now
38 * missing.
39 * - The recheck list is replaced with this new list.
41 * This system is designed to get the number of items and their names quickly,
42 * so that the auto-sizer can make a good guess.
44 * To get the Directory object, use dir_cache, which will automatically
45 * trigger a rescan if needed.
47 * To get notified when the Directory changes, use the dir_attach() and
48 * dir_detach() functions.
51 #include "config.h"
53 #include <gtk/gtk.h>
54 #include <errno.h>
55 #include <stdio.h>
56 #include <string.h>
58 #include "global.h"
60 #include "dir.h"
61 #include "diritem.h"
62 #include "support.h"
63 #include "gui_support.h"
64 #include "dir.h"
65 #include "fscache.h"
66 #include "mount.h"
67 #include "pixmaps.h"
68 #include "type.h"
69 #include "usericons.h"
70 #include "main.h"
72 #ifdef USE_DNOTIFY
73 /* Newer Linux kernels can tell us when the directories we are watching
74 * change, using the dnotify system.
76 static GHashTable *dnotify_fd_to_dir = NULL;
77 gboolean dnotify_wakeup_flag = FALSE;
78 static int dnotify_last_fd = -1;
79 #endif
81 /* For debugging. Can't detach when this is non-zero. */
82 static int in_callback = 0;
84 GFSCache *dir_cache = NULL;
86 /* Static prototypes */
87 static void update(Directory *dir, gchar *pathname, gpointer data);
88 static void set_idle_callback(Directory *dir);
89 static DirItem *insert_item(Directory *dir, const guchar *leafname);
90 static void remove_missing(Directory *dir, GPtrArray *keep);
91 static void dir_recheck(Directory *dir,
92 const guchar *path, const guchar *leafname);
93 static GPtrArray *hash_to_array(GHashTable *hash);
94 static void dir_force_update_item(Directory *dir, const gchar *leaf);
95 static Directory *dir_new(const char *pathname);
96 static void dir_rescan(Directory *dir);
97 #ifdef USE_DNOTIFY
98 static void dir_rescan_soon(Directory *dir);
99 static void dnotify_handler(int sig, siginfo_t *si, void *data);
100 #endif
102 /****************************************************************
103 * EXTERNAL INTERFACE *
104 ****************************************************************/
106 void dir_init(void)
108 dir_cache = g_fscache_new((GFSLoadFunc) dir_new,
109 (GFSUpdateFunc) update, NULL);
111 /* Check for dnotify support in the kernel */
112 #ifdef USE_DNOTIFY
114 struct sigaction act;
116 act.sa_sigaction = dnotify_handler;
117 sigemptyset(&act.sa_mask);
118 act.sa_flags = SA_SIGINFO;
119 sigaction(SIGRTMIN, &act, NULL);
121 /* Sometimes we get this instead of SIGRTMIN.
122 * Don't know why :-( but don't crash...
124 act.sa_handler = SIG_IGN;
125 sigemptyset(&act.sa_mask);
126 act.sa_flags = 0;
127 sigaction(SIGIO, &act, NULL);
129 dnotify_fd_to_dir = g_hash_table_new(NULL, NULL);
131 #endif
134 /* Periodically calls callback to notify about changes to the contents
135 * of the directory.
136 * Before this function returns, it calls the callback once to add all
137 * the items currently in the directory (unless the dir is empty).
138 * If we are not scanning, it also calls update(DIR_END_SCAN).
140 void dir_attach(Directory *dir, DirCallback callback, gpointer data)
142 DirUser *user;
143 GPtrArray *items;
145 g_return_if_fail(dir != NULL);
146 g_return_if_fail(callback != NULL);
148 user = g_new(DirUser, 1);
149 user->callback = callback;
150 user->data = data;
152 #ifdef USE_DNOTIFY
153 if (!dir->users)
155 int fd;
157 if (dir->dnotify_fd != -1)
158 g_warning("dir_attach: dnotify error\n");
160 fd = open(dir->pathname, O_RDONLY);
161 g_return_if_fail(g_hash_table_lookup(dnotify_fd_to_dir,
162 GINT_TO_POINTER(fd)) == NULL);
163 if (fd != -1)
165 dir->dnotify_fd = fd;
166 g_hash_table_insert(dnotify_fd_to_dir,
167 GINT_TO_POINTER(fd), dir);
168 fcntl(fd, F_SETSIG, SIGRTMIN);
169 fcntl(fd, F_NOTIFY, DN_CREATE | DN_DELETE | DN_RENAME |
170 DN_ATTRIB | DN_MULTISHOT);
173 #endif
175 dir->users = g_list_prepend(dir->users, user);
177 g_object_ref(dir);
179 items = hash_to_array(dir->known_items);
180 if (items->len)
181 callback(dir, DIR_ADD, items, data);
182 g_ptr_array_free(items, TRUE);
184 if (dir->needs_update && !dir->scanning)
185 dir_rescan(dir);
187 /* May start scanning if noone was watching before */
188 set_idle_callback(dir);
190 if (!dir->scanning)
191 callback(dir, DIR_END_SCAN, NULL, data);
194 /* Undo the effect of dir_attach */
195 void dir_detach(Directory *dir, DirCallback callback, gpointer data)
197 DirUser *user;
198 GList *list;
200 g_return_if_fail(dir != NULL);
201 g_return_if_fail(callback != NULL);
202 g_return_if_fail(in_callback == 0);
204 for (list = dir->users; list; list = list->next)
206 user = (DirUser *) list->data;
207 if (user->callback == callback && user->data == data)
209 g_free(user);
210 dir->users = g_list_remove(dir->users, user);
211 g_object_unref(dir);
213 /* May stop scanning if noone's watching */
214 set_idle_callback(dir);
216 #ifdef USE_DNOTIFY
217 if (!dir->users && dir->dnotify_fd != -1)
219 close(dir->dnotify_fd);
220 g_hash_table_remove(dnotify_fd_to_dir,
221 GINT_TO_POINTER(dir->dnotify_fd));
222 dir->dnotify_fd = -1;
224 #endif
225 return;
229 g_warning("dir_detach: Callback/data pair not attached!\n");
232 void dir_update(Directory *dir, gchar *pathname)
234 update(dir, pathname, NULL);
237 /* Rescan this directory */
238 void refresh_dirs(const char *path)
240 g_fscache_update(dir_cache, path);
243 /* When something has happened to a particular object, call this
244 * and all appropriate changes will be made.
246 void dir_check_this(const guchar *path)
248 guchar *real_path;
249 guchar *dir_path;
250 Directory *dir;
252 dir_path = g_path_get_dirname(path);
253 real_path = pathdup(dir_path);
254 g_free(dir_path);
256 dir = g_fscache_lookup_full(dir_cache, real_path,
257 FSCACHE_LOOKUP_PEEK, NULL);
258 if (dir)
260 dir_recheck(dir, real_path, g_basename(path));
261 g_object_unref(dir);
264 g_free(real_path);
267 #ifdef USE_DNOTIFY
268 static void drop_dnotify(gpointer key, gpointer value, gpointer data)
270 close(GPOINTER_TO_INT(key));
272 #endif
274 /* Used when we fork an action child, otherwise we can't delete or unmount
275 * any directory which we're watching!
277 void dir_drop_all_dnotifies(void)
279 #ifdef USE_DNOTIFY
280 g_hash_table_foreach(dnotify_fd_to_dir, drop_dnotify, NULL);
281 #endif
284 /* Tell watchers that this item has changed, but don't rescan.
285 * (used when thumbnail has been created for an item)
287 void dir_force_update_path(const gchar *path)
289 gchar *dir_path;
290 Directory *dir;
292 g_return_if_fail(path[0] == '/');
294 dir_path = g_path_get_dirname(path);
296 dir = g_fscache_lookup_full(dir_cache, dir_path, FSCACHE_LOOKUP_PEEK,
297 NULL);
298 if (dir)
300 dir_force_update_item(dir, g_basename(path));
301 g_object_unref(dir);
304 g_free(dir_path);
307 /* Ensure that 'leafname' is up-to-date. Returns the new/updated
308 * DirItem, or NULL if the file no longer exists.
310 DirItem *dir_update_item(Directory *dir, const gchar *leafname)
312 DirItem *item;
314 time(&diritem_recent_time);
315 item = insert_item(dir, leafname);
316 dir_merge_new(dir);
318 return item;
321 static int sort_names(const void *a, const void *b)
323 return strcmp(*((char **) a), *((char **) b));
326 static void free_recheck_list(Directory *dir)
328 destroy_glist(&dir->recheck_list);
331 /* If scanning state has changed then notify all filer windows */
332 static void dir_set_scanning(Directory *dir, gboolean scanning)
334 GList *next;
336 if (scanning == dir->scanning)
337 return;
339 in_callback++;
341 dir->scanning = scanning;
343 for (next = dir->users; next; next = next->next)
345 DirUser *user = (DirUser *) next->data;
347 user->callback(dir,
348 scanning ? DIR_START_SCAN : DIR_END_SCAN,
349 NULL, user->data);
352 in_callback--;
355 /* Notify everyone that the error status of the directory has changed */
356 static void dir_error_changed(Directory *dir)
358 GList *next;
360 in_callback++;
362 for (next = dir->users; next; next = next->next)
364 DirUser *user = (DirUser *) next->data;
366 user->callback(dir, DIR_ERROR_CHANGED, NULL, user->data);
369 in_callback--;
372 /* This is called in the background when there are items on the
373 * dir->recheck_list to process.
375 static gboolean recheck_callback(gpointer data)
377 Directory *dir = (Directory *) data;
378 GList *next;
379 guchar *leaf;
381 g_return_val_if_fail(dir != NULL, FALSE);
382 g_return_val_if_fail(dir->recheck_list != NULL, FALSE);
384 /* Remove the first name from the list */
385 next = dir->recheck_list;
386 dir->recheck_list = g_list_remove_link(dir->recheck_list, next);
387 leaf = (guchar *) next->data;
388 g_list_free_1(next);
390 /* usleep(800); */
392 insert_item(dir, leaf);
394 g_free(leaf);
396 if (dir->recheck_list)
397 return TRUE; /* Call again */
399 /* The recheck_list list empty. Stop scanning, unless
400 * needs_update, in which case we start scanning again.
403 dir_merge_new(dir);
405 dir->have_scanned = TRUE;
406 dir_set_scanning(dir, FALSE);
407 gtk_idle_remove(dir->idle_callback);
408 dir->idle_callback = 0;
410 if (dir->needs_update)
411 dir_rescan(dir);
413 return FALSE;
416 /* Add all the new items to the items array.
417 * Notify everyone who is watching us.
419 void dir_merge_new(Directory *dir)
421 GPtrArray *new = dir->new_items;
422 GPtrArray *up = dir->up_items;
423 GPtrArray *gone = dir->gone_items;
424 GList *list;
425 guint i;
427 in_callback++;
429 for (list = dir->users; list; list = list->next)
431 DirUser *user = (DirUser *) list->data;
433 if (new->len)
434 user->callback(dir, DIR_ADD, new, user->data);
435 if (up->len)
436 user->callback(dir, DIR_UPDATE, up, user->data);
437 if (gone->len)
438 user->callback(dir, DIR_REMOVE, gone, user->data);
441 in_callback--;
443 for (i = 0; i < new->len; i++)
445 DirItem *item = (DirItem *) new->pdata[i];
447 g_hash_table_insert(dir->known_items, item->leafname, item);
450 for (i = 0; i < gone->len; i++)
452 DirItem *item = (DirItem *) gone->pdata[i];
454 diritem_free(item);
457 g_ptr_array_set_size(gone, 0);
458 g_ptr_array_set_size(new, 0);
459 g_ptr_array_set_size(up, 0);
462 #ifdef USE_DNOTIFY
463 /* Called from the mainloop shortly after dnotify_handler */
464 void dnotify_wakeup(void)
466 Directory *dir;
468 dnotify_wakeup_flag = FALSE;
470 dir = g_hash_table_lookup(dnotify_fd_to_dir,
471 GINT_TO_POINTER(dnotify_last_fd));
473 if (dir)
474 dir_rescan_soon(dir);
476 #endif
478 /****************************************************************
479 * INTERNAL FUNCTIONS *
480 ****************************************************************/
482 #ifdef USE_DNOTIFY
483 static gint rescan_soon_timeout(gpointer data)
485 Directory *dir = (Directory *) data;
487 dir->rescan_timeout = -1;
488 if (dir->scanning)
489 dir->needs_update = TRUE;
490 else
491 dir_rescan(dir);
492 return FALSE;
495 /* Wait a fraction of a second and then rescan. If already waiting,
496 * this function does nothing.
498 static void dir_rescan_soon(Directory *dir)
500 if (dir->rescan_timeout != -1)
501 return;
502 dir->rescan_timeout = gtk_timeout_add(500, rescan_soon_timeout, dir);
504 #endif
506 static void free_items_array(GPtrArray *array)
508 guint i;
510 for (i = 0; i < array->len; i++)
512 DirItem *item = (DirItem *) array->pdata[i];
514 diritem_free(item);
517 g_ptr_array_free(array, TRUE);
520 /* Tell everyone watching that these items have gone */
521 static void notify_deleted(Directory *dir, GPtrArray *deleted)
523 GList *next;
525 if (!deleted->len)
526 return;
528 in_callback++;
530 for (next = dir->users; next; next = next->next)
532 DirUser *user = (DirUser *) next->data;
534 user->callback(dir, DIR_REMOVE, deleted, user->data);
537 in_callback--;
540 static void mark_unused(gpointer key, gpointer value, gpointer data)
542 DirItem *item = (DirItem *) value;
544 item->may_delete = TRUE;
547 static void keep_deleted(gpointer key, gpointer value, gpointer data)
549 DirItem *item = (DirItem *) value;
550 GPtrArray *deleted = (GPtrArray *) data;
552 if (item->may_delete)
553 g_ptr_array_add(deleted, item);
556 static gboolean check_unused(gpointer key, gpointer value, gpointer data)
558 DirItem *item = (DirItem *) value;
560 return item->may_delete;
563 /* Remove all the old items that have gone.
564 * Notify everyone who is watching us of the removed items.
566 static void remove_missing(Directory *dir, GPtrArray *keep)
568 GPtrArray *deleted;
569 guint i;
571 deleted = g_ptr_array_new();
573 /* Mark all current items as may_delete */
574 g_hash_table_foreach(dir->known_items, mark_unused, NULL);
576 /* Unmark all items also in 'keep' */
577 for (i = 0; i < keep->len; i++)
579 guchar *leaf = (guchar *) keep->pdata[i];
580 DirItem *item;
582 item = g_hash_table_lookup(dir->known_items, leaf);
584 if (item)
585 item->may_delete = FALSE;
588 /* Add each item still marked to 'deleted' */
589 g_hash_table_foreach(dir->known_items, keep_deleted, deleted);
591 /* Remove all items still marked */
592 g_hash_table_foreach_remove(dir->known_items, check_unused, NULL);
594 notify_deleted(dir, deleted);
596 free_items_array(deleted);
599 static gint notify_timeout(gpointer data)
601 Directory *dir = (Directory *) data;
603 g_return_val_if_fail(dir->notify_active == TRUE, FALSE);
605 dir_merge_new(dir);
607 dir->notify_active = FALSE;
608 g_object_unref(dir);
610 return FALSE;
613 /* Call dir_merge_new() after a while. */
614 static void delayed_notify(Directory *dir)
616 if (dir->notify_active)
617 return;
618 g_object_ref(dir);
619 gtk_timeout_add(1500, notify_timeout, dir);
620 dir->notify_active = TRUE;
623 /* Stat this item and add, update or remove it.
624 * Returns the new/updated item, if any.
625 * (leafname may be from the current DirItem item)
626 * Ensure diritem_recent_time is reasonably up-to-date before calling this.
628 static DirItem *insert_item(Directory *dir, const guchar *leafname)
630 const gchar *full_path;
631 DirItem *item;
632 DirItem old;
633 gboolean do_compare = FALSE; /* (old is filled in) */
635 if (leafname[0] == '.' && (leafname[1] == '\n' ||
636 (leafname[1] == '.' && leafname[2] == '\n')))
637 return NULL; /* Ignore '.' and '..' */
639 full_path = make_path(dir->pathname, leafname);
640 item = g_hash_table_lookup(dir->known_items, leafname);
642 if (item)
644 if (item->base_type != TYPE_UNKNOWN)
646 /* Preserve the old details so we can compare */
647 old = *item;
648 if (old.image)
649 g_object_ref(old.image);
650 do_compare = TRUE;
652 diritem_restat(full_path, item, &dir->stat_info);
654 else
656 /* Item isn't already here. This won't normally happen,
657 * because blank items are added when scanning, before
658 * we get here.
660 item = diritem_new(leafname);
661 diritem_restat(full_path, item, &dir->stat_info);
662 if (item->base_type == TYPE_ERROR &&
663 item->lstat_errno == ENOENT)
665 diritem_free(item);
666 return NULL;
668 g_ptr_array_add(dir->new_items, item);
672 if (item->base_type == TYPE_ERROR && item->lstat_errno == ENOENT)
674 /* Item has been deleted */
675 g_hash_table_remove(dir->known_items, item->leafname);
676 g_ptr_array_add(dir->gone_items, item);
677 if (do_compare && old.image)
678 g_object_unref(old.image);
679 delayed_notify(dir);
680 return NULL;
683 if (do_compare)
685 if (item->lstat_errno == old.lstat_errno
686 && item->base_type == old.base_type
687 && item->flags == old.flags
688 && item->size == old.size
689 && item->mode == old.mode
690 && item->atime == old.atime
691 && item->ctime == old.ctime
692 && item->mtime == old.mtime
693 && item->uid == old.uid
694 && item->gid == old.gid
695 && item->image == old.image
696 && item->mime_type == old.mime_type)
698 if (old.image)
699 g_object_unref(old.image);
700 return item;
702 if (old.image)
703 g_object_unref(old.image);
706 g_ptr_array_add(dir->up_items, item);
707 delayed_notify(dir);
709 return item;
712 static void update(Directory *dir, gchar *pathname, gpointer data)
714 g_free(dir->pathname);
715 dir->pathname = pathdup(pathname);
717 if (dir->scanning)
718 dir->needs_update = TRUE;
719 else
720 dir_rescan(dir);
723 /* If there is work to do, set the idle callback.
724 * Otherwise, stop scanning and unset the idle callback.
726 static void set_idle_callback(Directory *dir)
728 if (dir->recheck_list && dir->users)
730 /* Work to do, and someone's watching */
731 dir_set_scanning(dir, TRUE);
732 if (dir->idle_callback)
733 return;
734 time(&diritem_recent_time);
735 dir->idle_callback = gtk_idle_add(recheck_callback, dir);
736 /* Do the first call now (will remove the callback itself) */
737 recheck_callback(dir);
739 else
741 dir_set_scanning(dir, FALSE);
742 if (dir->idle_callback)
744 gtk_idle_remove(dir->idle_callback);
745 dir->idle_callback = 0;
750 /* See dir_force_update_path() */
751 static void dir_force_update_item(Directory *dir, const gchar *leaf)
753 GList *list;
754 GPtrArray *items;
755 DirItem *item;
757 items = g_ptr_array_new();
759 item = g_hash_table_lookup(dir->known_items, leaf);
760 if (!item)
761 goto out;
763 g_ptr_array_add(items, item);
765 in_callback++;
767 for (list = dir->users; list; list = list->next)
769 DirUser *user = (DirUser *) list->data;
771 user->callback(dir, DIR_UPDATE, items, user->data);
774 in_callback--;
776 out:
777 g_ptr_array_free(items, TRUE);
780 static void dir_recheck(Directory *dir,
781 const guchar *path, const guchar *leafname)
783 guchar *old = dir->pathname;
785 dir->pathname = g_strdup(path);
786 g_free(old);
788 time(&diritem_recent_time);
789 insert_item(dir, leafname);
792 static void to_array(gpointer key, gpointer value, gpointer data)
794 GPtrArray *array = (GPtrArray *) data;
796 g_ptr_array_add(array, value);
799 /* Convert a hash table to an unsorted GPtrArray.
800 * g_ptr_array_free() the result.
802 static GPtrArray *hash_to_array(GHashTable *hash)
804 GPtrArray *array;
806 array = g_ptr_array_new();
808 g_hash_table_foreach(hash, to_array, array);
810 return array;
813 static gpointer parent_class;
815 /* Note: dir_cache is never purged, so this shouldn't get called */
816 static void dir_finialize(GObject *object)
818 GPtrArray *items;
819 Directory *dir = (Directory *) object;
821 g_return_if_fail(dir->users == NULL);
823 g_print("[ dir finalize ]\n");
825 free_recheck_list(dir);
826 set_idle_callback(dir);
827 if (dir->rescan_timeout != -1)
828 gtk_timeout_remove(dir->rescan_timeout);
830 dir_merge_new(dir); /* Ensures new, up and gone are empty */
832 g_ptr_array_free(dir->up_items, TRUE);
833 g_ptr_array_free(dir->new_items, TRUE);
834 g_ptr_array_free(dir->gone_items, TRUE);
836 items = hash_to_array(dir->known_items);
837 free_items_array(items);
838 g_hash_table_destroy(dir->known_items);
840 g_free(dir->error);
841 g_free(dir->pathname);
843 G_OBJECT_CLASS(parent_class)->finalize(object);
846 static void directory_class_init(gpointer gclass, gpointer data)
848 GObjectClass *object = (GObjectClass *) gclass;
850 parent_class = g_type_class_peek_parent(gclass);
852 object->finalize = dir_finialize;
855 static void directory_init(GTypeInstance *object, gpointer gclass)
857 Directory *dir = (Directory *) object;
859 dir->known_items = g_hash_table_new(g_str_hash, g_str_equal);
860 dir->recheck_list = NULL;
861 dir->idle_callback = 0;
862 dir->scanning = FALSE;
863 dir->have_scanned = FALSE;
865 dir->users = NULL;
866 dir->needs_update = TRUE;
867 dir->notify_active = FALSE;
868 dir->pathname = NULL;
869 dir->error = NULL;
870 dir->rescan_timeout = -1;
871 #ifdef USE_DNOTIFY
872 dir->dnotify_fd = -1;
873 #endif
875 dir->new_items = g_ptr_array_new();
876 dir->up_items = g_ptr_array_new();
877 dir->gone_items = g_ptr_array_new();
880 static GType dir_get_type(void)
882 static GType type = 0;
884 if (!type)
886 static const GTypeInfo info =
888 sizeof (DirectoryClass),
889 NULL, /* base_init */
890 NULL, /* base_finalise */
891 directory_class_init,
892 NULL, /* class_finalise */
893 NULL, /* class_data */
894 sizeof(Directory),
895 0, /* n_preallocs */
896 directory_init
899 type = g_type_register_static(G_TYPE_OBJECT, "Directory",
900 &info, 0);
903 return type;
906 static Directory *dir_new(const char *pathname)
908 Directory *dir;
910 dir = g_object_new(dir_get_type(), NULL);
912 dir->pathname = g_strdup(pathname);
914 return dir;
917 /* Get the names of all files in the directory.
918 * Remove any DirItems that are no longer listed.
919 * Replace the recheck_list with the items found.
921 static void dir_rescan(Directory *dir)
923 GPtrArray *names;
924 DIR *d;
925 struct dirent *ent;
926 guint i;
927 const char *pathname;
928 int longest_len = -1;
929 GList *longest = NULL;
931 g_return_if_fail(dir != NULL);
933 pathname = dir->pathname;
935 dir->needs_update = FALSE;
937 names = g_ptr_array_new();
939 read_globicons();
940 mount_update(FALSE);
941 if (dir->error)
943 null_g_free(&dir->error);
944 dir_error_changed(dir);
947 /* Saves statting the parent for each item... */
948 if (mc_stat(pathname, &dir->stat_info))
950 dir->error = g_strdup_printf(_("Can't stat directory: %s"),
951 g_strerror(errno));
952 dir_error_changed(dir);
953 return; /* Report on attach */
956 d = mc_opendir(pathname);
957 if (!d)
959 dir->error = g_strdup_printf(_("Can't open directory: %s"),
960 g_strerror(errno));
961 dir_error_changed(dir);
962 return; /* Report on attach */
965 dir_set_scanning(dir, TRUE);
966 dir_merge_new(dir);
967 gdk_flush();
969 /* Make a list of all the names in the directory */
970 while ((ent = mc_readdir(d)))
972 if (ent->d_name[0] == '.')
974 if (ent->d_name[1] == '\0')
975 continue; /* Ignore '.' */
976 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
977 continue; /* Ignore '..' */
980 g_ptr_array_add(names, g_strdup(ent->d_name));
982 mc_closedir(d);
984 /* Sort, so the names are scanned in a sensible order */
985 qsort(names->pdata, names->len, sizeof(guchar *), sort_names);
987 /* Compare the list with the current DirItems, removing
988 * any that are missing.
990 remove_missing(dir, names);
992 free_recheck_list(dir);
994 /* For each name found, add it to the recheck_list.
995 * If the item is new, put a blank place-holder item in the directory.
997 for (i = 0; i < names->len; i++)
999 guchar *name = names->pdata[i];
1000 int len = strlen(name);
1002 dir->recheck_list = g_list_prepend(dir->recheck_list, name);
1003 if (!g_hash_table_lookup(dir->known_items, name))
1005 DirItem *new;
1007 new = diritem_new(name);
1008 g_ptr_array_add(dir->new_items, new);
1011 if (name[0] != '.' && len > longest_len)
1013 longest_len = len;
1014 longest = dir->recheck_list;
1018 dir_merge_new(dir);
1020 dir->recheck_list = g_list_reverse(dir->recheck_list);
1022 if (longest)
1024 gpointer data = longest->data;
1026 /* Move the longest item to the start. Helps with
1027 * auto sizing.
1029 dir->recheck_list = g_list_remove_link(dir->recheck_list,
1030 longest);
1031 dir->recheck_list = g_list_prepend(dir->recheck_list, data);
1034 g_ptr_array_free(names, TRUE);
1036 set_idle_callback(dir);
1037 dir_merge_new(dir);
1040 #ifdef USE_DNOTIFY
1041 /* Signal handler - don't do anything dangerous here */
1042 static void dnotify_handler(int sig, siginfo_t *si, void *data)
1044 /* Note: there is currently only one place to store the fd,
1045 * so we'll miss updates to several directories if they happen
1046 * close together.
1048 dnotify_last_fd = si->si_fd;
1049 dnotify_wakeup_flag = TRUE;
1050 write(to_wakeup_pipe, "\0", 1); /* Wake up! */
1052 #endif