Get times from GIO correctly
[rox-filer.git] / ROX-Filer / src / dir.c
blobafb246d40d8faa86950742f94f00cd4e3f051bf2
1 /*
2 * ROX-Filer, filer for the ROX desktop project
3 * Copyright (C) 2006, Thomas Leonard and others (see changelog for details).
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the Free
6 * Software Foundation; either version 2 of the License, or (at your option)
7 * any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16 * Place, Suite 330, Boston, MA 02111-1307 USA
19 /* dir.c - directory scanning and caching */
21 /* How it works:
23 * A Directory contains a list DirItems, each having a name and some details
24 * (size, image, owner, etc).
26 * There is a list of file names that need to be rechecked. While this
27 * list is non-empty, items are taken from the list in an idle callback
28 * and checked. Missing items are removed from the Directory, new items are
29 * added and existing items are updated if they've changed.
31 * When a whole directory is to be rescanned:
33 * - A list of all filenames in the directory is fetched, without any
34 * of the extra details.
35 * - This list is compared to the current DirItems, removing any that are now
36 * missing.
37 * - Each window onto the directory is asked which items it will actually
38 * display, and the union of these sets is the new recheck list.
40 * This system is designed to get the number of items and their names quickly,
41 * so that the auto-sizer can make a good guess. It also prevents checking
42 * hidden files if they're not going to be displayed.
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 /* For debugging. Can't detach when this is non-zero. */
73 static int in_callback = 0;
75 GHashTable *dir_cache_new = NULL; /* URI -> Directory */
77 /* Static prototypes */
78 static void update(Directory *dir, gchar *pathname, gpointer data);
79 static void set_idle_callback(Directory *dir);
80 static DirItem *insert_item(Directory *dir, const guchar *leafname);
81 static void remove_missing(Directory *dir, GPtrArray *keep);
82 static void dir_recheck(Directory *dir,
83 const guchar *path, const guchar *leafname);
84 static GPtrArray *hash_to_array(GHashTable *hash);
85 static void dir_force_update_item(Directory *dir, const gchar *leaf);
86 static Directory *dir_new(const char *uri);
87 static void dir_rescan(Directory *dir);
89 /****************************************************************
90 * EXTERNAL INTERFACE *
91 ****************************************************************/
93 void dir_init(void)
95 dir_cache_new = g_hash_table_new(g_str_hash, g_str_equal);
98 /* Get a new or existing Directory object.
99 * If create is false, only return an existing object.
100 * If true, create one if necessary.
101 * Call g_object_unref() when done.
102 * Will return null if directory doesn't exist : TODO
104 Directory *dir_lookup(const char *uri, gboolean may_create)
106 Directory *dir;
108 dir = g_hash_table_lookup(dir_cache_new, uri);
110 if (dir == NULL)
112 dir = dir_new(uri);
113 g_hash_table_insert(dir_cache_new, dir->pathname, dir);
114 g_object_ref(dir); /* One ref for the cache */
117 g_object_ref(dir); /* One ref for the caller */
119 return dir;
122 static void dir_changed_cb(GFileMonitor *monitor, GFile *file, GFile *other_file,
123 GFileMonitorEvent event_type, Directory *dir)
125 // TODO: don't do a full rescan!
126 dir_rescan(dir);
129 /* Periodically calls callback to notify about changes to the contents
130 * of the directory.
131 * Before this function returns, it calls the callback once to add all
132 * the items currently in the directory (unless the dir is empty).
133 * It then calls callback(DIR_QUEUE_INTERESTING) to find out which items the
134 * caller cares about.
135 * If we are not scanning, it also calls callback(DIR_END_SCAN).
137 void dir_attach(Directory *dir, DirCallback callback, gpointer data)
139 DirUser *user;
140 GPtrArray *items;
142 g_return_if_fail(dir != NULL);
143 g_return_if_fail(callback != NULL);
145 user = g_new(DirUser, 1);
146 user->callback = callback;
147 user->data = data;
149 if (!dir->users)
151 g_return_if_fail(dir->monitor == NULL);
152 dir->monitor = g_file_monitor_directory(dir->gfile, G_FILE_MONITOR_NONE, NULL, NULL);
153 if (dir->monitor)
154 g_signal_connect(dir->monitor, "changed", (GCallback) dir_changed_cb, dir);
155 else
156 g_warning("Failed to monitor directory '%s'", dir->pathname);
159 dir->users = g_list_prepend(dir->users, user);
161 g_object_ref(dir);
163 items = hash_to_array(dir->known_items);
164 if (items->len)
165 callback(dir, DIR_ADD, items, data);
166 g_ptr_array_free(items, TRUE);
168 if (dir->needs_update && !dir->scanning)
169 dir_rescan(dir);
170 else
171 callback(dir, DIR_QUEUE_INTERESTING, NULL, data);
173 /* May start scanning if noone was watching before */
174 set_idle_callback(dir);
176 if (!dir->scanning)
177 callback(dir, DIR_END_SCAN, NULL, data);
180 /* Undo the effect of dir_attach */
181 void dir_detach(Directory *dir, DirCallback callback, gpointer data)
183 DirUser *user;
184 GList *list;
186 g_return_if_fail(dir != NULL);
187 g_return_if_fail(callback != NULL);
188 g_return_if_fail(in_callback == 0);
190 for (list = dir->users; list; list = list->next)
192 user = (DirUser *) list->data;
193 if (user->callback == callback && user->data == data)
195 g_free(user);
196 dir->users = g_list_remove(dir->users, user);
197 g_object_unref(dir);
199 /* May stop scanning if noone's watching */
200 set_idle_callback(dir);
202 if (!dir->users && dir->monitor)
204 g_object_unref(dir->monitor);
205 dir->monitor = NULL;
208 return;
212 g_warning("dir_detach: Callback/data pair not attached!\n");
215 void dir_update(Directory *dir, gchar *pathname)
217 update(dir, pathname, NULL);
220 /* Rescan this directory */
221 void refresh_dirs(const char *path)
223 // TODO
224 //g_fscache_update(dir_cache, path);
227 /* When something has happened to a particular object, call this
228 * and all appropriate changes will be made.
230 void dir_check_this(const guchar *path)
232 guchar *real_path;
233 guchar *dir_path;
234 Directory *dir;
236 dir_path = g_path_get_dirname(path);
237 real_path = pathdup(dir_path);
238 g_free(dir_path);
240 dir = dir_lookup(real_path, FALSE);
241 if (dir)
243 dir_recheck(dir, real_path, g_basename(path));
244 g_object_unref(dir);
247 g_free(real_path);
250 /* Used when we fork an action child, otherwise we can't delete or unmount
251 * any directory which we're watching!
253 void dir_drop_all_dnotifies(void)
255 /* TODO: still needed with GIO? */
258 /* Tell watchers that this item has changed, but don't rescan.
259 * (used when thumbnail has been created for an item)
261 void dir_force_update_path(const gchar *path)
263 gchar *dir_path;
264 Directory *dir;
266 g_return_if_fail(path[0] == '/');
268 dir_path = g_path_get_dirname(path);
270 dir = NULL; //g_fscache_lookup_full(dir_cache, dir_path, FSCACHE_LOOKUP_PEEK, NULL); TODO
271 if (dir)
273 dir_force_update_item(dir, g_basename(path));
274 g_object_unref(dir);
277 g_free(dir_path);
280 /* Ensure that 'leafname' is up-to-date. Returns the new/updated
281 * DirItem, or NULL if the file no longer exists.
283 DirItem *dir_update_item(Directory *dir, const gchar *leafname)
285 DirItem *item;
287 time(&diritem_recent_time);
288 item = insert_item(dir, leafname);
289 dir_merge_new(dir);
291 return item;
294 /* Add item to the recheck_list if it's marked as needing it.
295 * Item must have ITEM_FLAG_NEED_RESCAN_QUEUE.
296 * Items on the list will get checked later in an idle callback.
298 void dir_queue_recheck(Directory *dir, DirItem *item)
300 g_return_if_fail(dir != NULL);
301 g_return_if_fail(item != NULL);
302 g_return_if_fail(item->flags & ITEM_FLAG_NEED_RESCAN_QUEUE);
304 dir->recheck_list = g_list_prepend(dir->recheck_list,
305 g_strdup(item->leafname));
306 item->flags &= ~ITEM_FLAG_NEED_RESCAN_QUEUE;
309 static void free_recheck_list(Directory *dir)
311 destroy_glist(&dir->recheck_list);
314 /* If scanning state has changed then notify all filer windows */
315 static void dir_set_scanning(Directory *dir, gboolean scanning)
317 GList *next;
319 if (scanning == dir->scanning)
320 return;
322 in_callback++;
324 dir->scanning = scanning;
326 for (next = dir->users; next; next = next->next)
328 DirUser *user = (DirUser *) next->data;
330 user->callback(dir,
331 scanning ? DIR_START_SCAN : DIR_END_SCAN,
332 NULL, user->data);
335 #if 0
336 /* Useful for profiling */
337 if (!scanning)
339 g_print("Done\n");
340 exit(0);
342 #endif
344 in_callback--;
347 /* Notify everyone that the error status of the directory has changed */
348 static void dir_error_changed(Directory *dir)
350 GList *next;
352 in_callback++;
354 for (next = dir->users; next; next = next->next)
356 DirUser *user = (DirUser *) next->data;
358 user->callback(dir, DIR_ERROR_CHANGED, NULL, user->data);
361 in_callback--;
364 /* This is called in the background when there are items on the
365 * dir->recheck_list to process.
367 static gboolean recheck_callback(gpointer data)
369 Directory *dir = (Directory *) data;
370 GList *next;
371 guchar *leaf;
373 g_return_val_if_fail(dir != NULL, FALSE);
374 g_return_val_if_fail(dir->recheck_list != NULL, FALSE);
376 /* Remove the first name from the list */
377 next = dir->recheck_list;
378 dir->recheck_list = g_list_remove_link(dir->recheck_list, next);
379 leaf = (guchar *) next->data;
380 g_list_free_1(next);
382 /* usleep(800); */
384 insert_item(dir, leaf);
386 g_free(leaf);
388 if (dir->recheck_list)
389 return TRUE; /* Call again */
391 /* The recheck_list list empty. Stop scanning, unless
392 * needs_update, in which case we start scanning again.
395 dir_merge_new(dir);
397 dir->have_scanned = TRUE;
398 dir_set_scanning(dir, FALSE);
399 g_source_remove(dir->idle_callback);
400 dir->idle_callback = 0;
402 if (dir->needs_update)
403 dir_rescan(dir);
405 return FALSE;
408 /* Add all the new items to the items array.
409 * Notify everyone who is watching us.
411 void dir_merge_new(Directory *dir)
413 GPtrArray *new = dir->new_items;
414 GPtrArray *up = dir->up_items;
415 GPtrArray *gone = dir->gone_items;
416 GList *list;
417 guint i;
419 in_callback++;
421 for (list = dir->users; list; list = list->next)
423 DirUser *user = (DirUser *) list->data;
425 if (new->len)
426 user->callback(dir, DIR_ADD, new, user->data);
427 if (up->len)
428 user->callback(dir, DIR_UPDATE, up, user->data);
429 if (gone->len)
430 user->callback(dir, DIR_REMOVE, gone, user->data);
433 in_callback--;
435 for (i = 0; i < new->len; i++)
437 DirItem *item = (DirItem *) new->pdata[i];
439 g_hash_table_insert(dir->known_items, item->leafname, item);
442 for (i = 0; i < gone->len; i++)
444 DirItem *item = (DirItem *) gone->pdata[i];
446 diritem_free(item);
449 g_ptr_array_set_size(gone, 0);
450 g_ptr_array_set_size(new, 0);
451 g_ptr_array_set_size(up, 0);
454 /****************************************************************
455 * INTERNAL FUNCTIONS *
456 ****************************************************************/
458 static void free_items_array(GPtrArray *array)
460 guint i;
462 for (i = 0; i < array->len; i++)
464 DirItem *item = (DirItem *) array->pdata[i];
466 diritem_free(item);
469 g_ptr_array_free(array, TRUE);
472 /* Tell everyone watching that these items have gone */
473 static void notify_deleted(Directory *dir, GPtrArray *deleted)
475 GList *next;
477 if (!deleted->len)
478 return;
480 in_callback++;
482 for (next = dir->users; next; next = next->next)
484 DirUser *user = (DirUser *) next->data;
486 user->callback(dir, DIR_REMOVE, deleted, user->data);
489 in_callback--;
492 static void mark_unused(gpointer key, gpointer value, gpointer data)
494 DirItem *item = (DirItem *) value;
496 item->may_delete = TRUE;
499 static void keep_deleted(gpointer key, gpointer value, gpointer data)
501 DirItem *item = (DirItem *) value;
502 GPtrArray *deleted = (GPtrArray *) data;
504 if (item->may_delete)
505 g_ptr_array_add(deleted, item);
508 static gboolean check_unused(gpointer key, gpointer value, gpointer data)
510 DirItem *item = (DirItem *) value;
512 return item->may_delete;
515 /* Remove all the old items that have gone.
516 * Notify everyone who is watching us of the removed items.
518 static void remove_missing(Directory *dir, GPtrArray *keep)
520 GPtrArray *deleted;
521 guint i;
523 deleted = g_ptr_array_new();
525 /* Mark all current items as may_delete */
526 g_hash_table_foreach(dir->known_items, mark_unused, NULL);
528 /* Unmark all items also in 'keep' */
529 for (i = 0; i < keep->len; i++)
531 guchar *leaf = (guchar *) keep->pdata[i];
532 DirItem *item;
534 item = g_hash_table_lookup(dir->known_items, leaf);
536 if (item)
537 item->may_delete = FALSE;
540 /* Add each item still marked to 'deleted' */
541 g_hash_table_foreach(dir->known_items, keep_deleted, deleted);
543 /* Remove all items still marked */
544 g_hash_table_foreach_remove(dir->known_items, check_unused, NULL);
546 notify_deleted(dir, deleted);
548 free_items_array(deleted);
551 static gint notify_timeout(gpointer data)
553 Directory *dir = (Directory *) data;
555 g_return_val_if_fail(dir->notify_active == TRUE, FALSE);
557 dir_merge_new(dir);
559 dir->notify_active = FALSE;
560 g_object_unref(dir);
562 return FALSE;
565 /* Call dir_merge_new() after a while. */
566 static void delayed_notify(Directory *dir)
568 if (dir->notify_active)
569 return;
570 g_object_ref(dir);
571 g_timeout_add(1500, notify_timeout, dir);
572 dir->notify_active = TRUE;
575 /* Stat this item and add, update or remove it.
576 * Returns the new/updated item, if any.
577 * (leafname may be from the current DirItem item)
578 * Ensure diritem_recent_time is reasonably up-to-date before calling this.
580 static DirItem *insert_item(Directory *dir, const guchar *leafname)
582 GFile *full_path;
583 DirItem *item;
584 DirItem old;
585 gboolean do_compare = FALSE; /* (old is filled in) */
587 if (leafname[0] == '.' && (leafname[1] == '\n' ||
588 (leafname[1] == '.' && leafname[2] == '\n')))
589 return NULL; /* Ignore '.' and '..' */
591 full_path = g_file_get_child(dir->gfile, leafname);
592 item = g_hash_table_lookup(dir->known_items, leafname);
594 if (item)
596 if (item->base_type != TYPE_UNKNOWN)
598 /* Preserve the old details so we can compare */
599 old = *item;
600 if (old._image)
601 g_object_ref(old._image);
602 do_compare = TRUE;
604 diritem_restat_gfile(full_path, item);
605 g_object_unref(full_path);
607 else
609 /* Item isn't already here. This won't normally happen,
610 * because blank items are added when scanning, before
611 * we get here.
613 item = diritem_new(leafname);
614 diritem_restat_gfile(full_path, item);
615 g_object_unref(full_path);
616 if (item->base_type == TYPE_ERROR &&
617 item->lstat_errno == ENOENT)
619 diritem_free(item);
620 return NULL;
622 g_ptr_array_add(dir->new_items, item);
626 /* No need to queue the item for scanning. If we got here because
627 * the item was queued, this flag will normally already be clear.
629 item->flags &= ~ITEM_FLAG_NEED_RESCAN_QUEUE;
631 if (item->base_type == TYPE_ERROR && item->lstat_errno == ENOENT)
633 /* Item has been deleted */
634 g_hash_table_remove(dir->known_items, item->leafname);
635 g_ptr_array_add(dir->gone_items, item);
636 if (do_compare && old._image)
637 g_object_unref(old._image);
638 delayed_notify(dir);
639 return NULL;
642 if (do_compare)
644 /* It's a bit inefficient that we force the image to be
645 * loaded here, if we had an old image.
647 if (item->lstat_errno == old.lstat_errno
648 && item->base_type == old.base_type
649 && item->flags == old.flags
650 && item->size == old.size
651 && item->mode == old.mode
652 && item->atime == old.atime
653 && item->ctime == old.ctime
654 && item->mtime == old.mtime
655 && item->uid == old.uid
656 && item->gid == old.gid
657 && item->mime_type == old.mime_type
658 && (old._image == NULL || di_image(item) == old._image))
660 if (old._image)
661 g_object_unref(old._image);
662 return item;
664 if (old._image)
665 g_object_unref(old._image);
668 g_ptr_array_add(dir->up_items, item);
669 delayed_notify(dir);
671 return item;
674 static void update(Directory *dir, gchar *pathname, gpointer data)
676 /* TODO: gfile */
677 g_free(dir->pathname);
678 dir->pathname = pathdup(pathname);
680 if (dir->scanning)
681 dir->needs_update = TRUE;
682 else
683 dir_rescan(dir);
686 /* If there is work to do, set the idle callback.
687 * Otherwise, stop scanning and unset the idle callback.
689 static void set_idle_callback(Directory *dir)
691 if (dir->recheck_list && dir->users)
693 /* Work to do, and someone's watching */
694 dir_set_scanning(dir, TRUE);
695 if (dir->idle_callback)
696 return;
697 time(&diritem_recent_time);
698 dir->idle_callback = g_idle_add(recheck_callback, dir);
699 /* Do the first call now (will remove the callback itself) */
700 recheck_callback(dir);
702 else
704 dir_set_scanning(dir, FALSE);
705 if (dir->idle_callback)
707 g_source_remove(dir->idle_callback);
708 dir->idle_callback = 0;
713 /* See dir_force_update_path() */
714 static void dir_force_update_item(Directory *dir, const gchar *leaf)
716 GList *list;
717 GPtrArray *items;
718 DirItem *item;
720 items = g_ptr_array_new();
722 item = g_hash_table_lookup(dir->known_items, leaf);
723 if (!item)
724 goto out;
726 g_ptr_array_add(items, item);
728 in_callback++;
730 for (list = dir->users; list; list = list->next)
732 DirUser *user = (DirUser *) list->data;
734 user->callback(dir, DIR_UPDATE, items, user->data);
737 in_callback--;
739 out:
740 g_ptr_array_free(items, TRUE);
743 static void dir_recheck(Directory *dir,
744 const guchar *path, const guchar *leafname)
746 guchar *old = dir->pathname;
748 dir->pathname = g_strdup(path);
749 g_free(old);
751 time(&diritem_recent_time);
752 insert_item(dir, leafname);
755 static void to_array(gpointer key, gpointer value, gpointer data)
757 GPtrArray *array = (GPtrArray *) data;
759 g_ptr_array_add(array, value);
762 /* Convert a hash table to an unsorted GPtrArray.
763 * g_ptr_array_free() the result.
765 static GPtrArray *hash_to_array(GHashTable *hash)
767 GPtrArray *array;
769 array = g_ptr_array_new();
771 g_hash_table_foreach(hash, to_array, array);
773 return array;
776 static gpointer parent_class;
778 /* Note: dir_cache is never purged, so this shouldn't get called */
779 static void dir_finialize(GObject *object)
781 GPtrArray *items;
782 Directory *dir = (Directory *) object;
784 g_return_if_fail(dir->users == NULL);
786 g_print("[ dir finalize ]\n");
788 free_recheck_list(dir);
789 set_idle_callback(dir);
790 if (dir->rescan_timeout != -1)
791 g_source_remove(dir->rescan_timeout);
793 dir_merge_new(dir); /* Ensures new, up and gone are empty */
795 g_ptr_array_free(dir->up_items, TRUE);
796 g_ptr_array_free(dir->new_items, TRUE);
797 g_ptr_array_free(dir->gone_items, TRUE);
799 items = hash_to_array(dir->known_items);
800 free_items_array(items);
801 g_hash_table_destroy(dir->known_items);
803 g_free(dir->error);
804 g_free(dir->pathname);
806 G_OBJECT_CLASS(parent_class)->finalize(object);
809 static void directory_class_init(gpointer gclass, gpointer data)
811 GObjectClass *object = (GObjectClass *) gclass;
813 parent_class = g_type_class_peek_parent(gclass);
815 object->finalize = dir_finialize;
818 static void directory_init(GTypeInstance *object, gpointer gclass)
820 Directory *dir = (Directory *) object;
822 dir->known_items = g_hash_table_new(g_str_hash, g_str_equal);
823 dir->gfile = NULL;
824 dir->monitor = NULL;
825 dir->recheck_list = NULL;
826 dir->idle_callback = 0;
827 dir->scanning = FALSE;
828 dir->have_scanned = FALSE;
830 dir->users = NULL;
831 dir->needs_update = TRUE;
832 dir->notify_active = FALSE;
833 dir->pathname = NULL;
834 dir->error = NULL;
835 dir->rescan_timeout = -1;
837 dir->new_items = g_ptr_array_new();
838 dir->up_items = g_ptr_array_new();
839 dir->gone_items = g_ptr_array_new();
842 static GType dir_get_type(void)
844 static GType type = 0;
846 if (!type)
848 static const GTypeInfo info =
850 sizeof (DirectoryClass),
851 NULL, /* base_init */
852 NULL, /* base_finalise */
853 directory_class_init,
854 NULL, /* class_finalise */
855 NULL, /* class_data */
856 sizeof(Directory),
857 0, /* n_preallocs */
858 directory_init
859 // TODO: finalise?
862 type = g_type_register_static(G_TYPE_OBJECT, "Directory",
863 &info, 0);
866 return type;
869 static Directory *dir_new(const char *uri)
871 Directory *dir;
873 dir = g_object_new(dir_get_type(), NULL);
875 dir->gfile = g_file_new_for_uri(uri);
876 dir->pathname = g_strdup(uri);
878 return dir;
881 static void dir_rescan_internal(Directory *dir, GError **error)
883 GFileInfo *info;
884 GFileEnumerator *iter;
885 GPtrArray *names;
886 guint i;
887 GList *next;
889 info = g_file_query_info(dir->gfile, "unix::*", G_FILE_QUERY_INFO_NONE, NULL, error);
890 if (!info)
891 return;
892 dir->stat_info.st_ino = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_UNIX_INODE);
893 dir->stat_info.st_dev = g_file_info_get_attribute_uint32(info, G_FILE_ATTRIBUTE_UNIX_DEVICE);
894 g_object_unref(info);
896 iter = g_file_enumerate_children(dir->gfile, USEFUL_GIO_ATTRS, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, error);
897 if (!iter)
898 return
900 dir_set_scanning(dir, TRUE);
901 dir_merge_new(dir);
902 gdk_flush();
904 names = g_ptr_array_new();
906 /* Make a list of all the names in the directory */
907 while ((info = g_file_enumerator_next_file(iter, NULL, error)))
909 const char *name;
911 if (*error)
913 g_warning("Error scanning directory: %s", (*error)->message);
914 g_error_free(*error);
915 *error = NULL;
916 continue;
919 name = g_file_info_get_attribute_byte_string(info, G_FILE_ATTRIBUTE_STANDARD_NAME);
920 g_return_if_fail(name != NULL);
922 if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0')))
924 /* Skip '.' and '..' */
926 else
928 g_ptr_array_add(names, g_strdup(name));
931 g_object_unref(info);
933 g_object_unref(iter);
935 /* Compare the list with the current DirItems, removing
936 * any that are missing.
938 remove_missing(dir, names);
940 free_recheck_list(dir);
942 /* For each name found, mark it as needing to be put on the rescan
943 * list at some point in the future.
944 * If the item is new, put a blank place-holder item in the directory.
946 for (i = 0; i < names->len; i++)
948 DirItem *old;
949 guchar *name = names->pdata[i];
951 old = g_hash_table_lookup(dir->known_items, name);
952 if (old)
954 /* This flag is cleared when the item is added
955 * to the rescan list.
957 old->flags |= ITEM_FLAG_NEED_RESCAN_QUEUE;
959 else
961 DirItem *new;
963 new = diritem_new(name);
964 g_ptr_array_add(dir->new_items, new);
969 dir_merge_new(dir);
971 /* Ask everyone which items they need to display, and add them to
972 * the recheck list. Typically, this means we don't waste time
973 * scanning hidden items.
975 in_callback++;
976 for (next = dir->users; next; next = next->next)
978 DirUser *user = (DirUser *) next->data;
979 user->callback(dir,
980 DIR_QUEUE_INTERESTING,
981 NULL, user->data);
983 in_callback--;
985 g_ptr_array_free(names, TRUE);
987 set_idle_callback(dir);
988 dir_merge_new(dir);
991 /* Get the names of all files in the directory.
992 * Remove any DirItems that are no longer listed.
993 * Replace the recheck_list with the items found.
995 static void dir_rescan(Directory *dir)
997 GError *error = NULL;
999 g_return_if_fail(dir != NULL);
1001 dir->needs_update = FALSE;
1003 read_globicons();
1004 mount_update(FALSE);
1005 if (dir->error)
1007 null_g_free(&dir->error);
1008 dir_error_changed(dir);
1011 dir_rescan_internal(dir, &error);
1013 if (error)
1015 dir->error = g_strdup(error->message);
1016 dir_error_changed(dir); /* Report on attach */
1017 g_error_free(error);