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)
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
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 */
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
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.
63 #include "gui_support.h"
69 #include "usericons.h"
73 static GHashTable
*notify_fd_to_dir
= NULL
;
76 # include <sys/inotify.h>
77 GIOChannel
*inotify_channel
;
78 static int inotify_fd
;
81 /* Newer Linux kernels can tell us when the directories we are watching
82 * change, using the dnotify system.
84 gboolean dnotify_wakeup_flag
= FALSE
;
85 static int dnotify_last_fd
= -1;
88 /* For debugging. Can't detach when this is non-zero. */
89 static int in_callback
= 0;
91 GFSCache
*dir_cache
= NULL
;
93 /* Static prototypes */
94 static void update(Directory
*dir
, gchar
*pathname
, gpointer data
);
95 static void set_idle_callback(Directory
*dir
);
96 static DirItem
*insert_item(Directory
*dir
, const guchar
*leafname
);
97 static void remove_missing(Directory
*dir
, GPtrArray
*keep
);
98 static void dir_recheck(Directory
*dir
,
99 const guchar
*path
, const guchar
*leafname
);
100 static GPtrArray
*hash_to_array(GHashTable
*hash
);
101 static void dir_force_update_item(Directory
*dir
, const gchar
*leaf
);
102 static Directory
*dir_new(const char *pathname
);
103 static void dir_rescan(Directory
*dir
);
105 static void dir_rescan_soon(Directory
*dir
);
107 static gboolean
inotify_handler(GIOChannel
*source
, GIOCondition condition
,
110 static void dnotify_handler(int sig
, siginfo_t
*si
, void *data
);
114 /****************************************************************
115 * EXTERNAL INTERFACE *
116 ****************************************************************/
120 dir_cache
= g_fscache_new((GFSLoadFunc
) dir_new
,
121 (GFSUpdateFunc
) update
, NULL
);
124 notify_fd_to_dir
= g_hash_table_new(NULL
, NULL
);
127 inotify_fd
= inotify_init();
128 inotify_channel
= g_io_channel_unix_new(inotify_fd
);
129 g_io_add_watch(inotify_channel
, G_IO_IN
, inotify_handler
, NULL
);
134 struct sigaction act
;
136 act
.sa_sigaction
= dnotify_handler
;
137 sigemptyset(&act
.sa_mask
);
138 act
.sa_flags
= SA_SIGINFO
;
139 sigaction(SIGRTMIN
, &act
, NULL
);
141 /* Sometimes we get this instead of SIGRTMIN.
142 * Don't know why :-( but don't crash...
144 act
.sa_handler
= SIG_IGN
;
145 sigemptyset(&act
.sa_mask
);
147 sigaction(SIGIO
, &act
, NULL
);
154 /* Periodically calls callback to notify about changes to the contents
156 * Before this function returns, it calls the callback once to add all
157 * the items currently in the directory (unless the dir is empty).
158 * It then calls callback(DIR_QUEUE_INTERESTING) to find out which items the
159 * caller cares about.
160 * If we are not scanning, it also calls callback(DIR_END_SCAN).
162 void dir_attach(Directory
*dir
, DirCallback callback
, gpointer data
)
167 g_return_if_fail(dir
!= NULL
);
168 g_return_if_fail(callback
!= NULL
);
170 user
= g_new(DirUser
, 1);
171 user
->callback
= callback
;
179 if (dir
->notify_fd
!= -1)
180 g_warning("dir_attach: inotify error\n");
182 fd
= inotify_add_watch( inotify_fd
,
184 IN_CREATE
| IN_DELETE
| IN_MOVE
|
187 g_return_if_fail(g_hash_table_lookup(notify_fd_to_dir
,
188 GINT_TO_POINTER(fd
)) == NULL
);
193 g_hash_table_insert(notify_fd_to_dir
,
194 GINT_TO_POINTER(fd
), dir
);
203 if (dir
->notify_fd
!= -1)
204 g_warning("dir_attach: dnotify error\n");
206 fd
= open(dir
->pathname
, O_RDONLY
);
207 g_return_if_fail(g_hash_table_lookup(notify_fd_to_dir
,
208 GINT_TO_POINTER(fd
)) == NULL
);
212 g_hash_table_insert(notify_fd_to_dir
,
213 GINT_TO_POINTER(fd
), dir
);
214 fcntl(fd
, F_SETSIG
, SIGRTMIN
);
215 fcntl(fd
, F_NOTIFY
, DN_CREATE
| DN_DELETE
| DN_RENAME
|
216 DN_ATTRIB
| DN_MULTISHOT
);
221 dir
->users
= g_list_prepend(dir
->users
, user
);
225 items
= hash_to_array(dir
->known_items
);
227 callback(dir
, DIR_ADD
, items
, data
);
228 g_ptr_array_free(items
, TRUE
);
230 if (dir
->needs_update
&& !dir
->scanning
)
233 callback(dir
, DIR_QUEUE_INTERESTING
, NULL
, data
);
235 /* May start scanning if noone was watching before */
236 set_idle_callback(dir
);
239 callback(dir
, DIR_END_SCAN
, NULL
, data
);
242 /* Undo the effect of dir_attach */
243 void dir_detach(Directory
*dir
, DirCallback callback
, gpointer data
)
248 g_return_if_fail(dir
!= NULL
);
249 g_return_if_fail(callback
!= NULL
);
250 g_return_if_fail(in_callback
== 0);
252 for (list
= dir
->users
; list
; list
= list
->next
)
254 user
= (DirUser
*) list
->data
;
255 if (user
->callback
== callback
&& user
->data
== data
)
258 dir
->users
= g_list_remove(dir
->users
, user
);
261 /* May stop scanning if noone's watching */
262 set_idle_callback(dir
);
265 if (!dir
->users
&& dir
->notify_fd
!= -1)
268 close(dir
->notify_fd
);
270 g_hash_table_remove(notify_fd_to_dir
,
271 GINT_TO_POINTER(dir
->notify_fd
));
275 if (dir
->inotify_source
) {
276 g_source_remove(dir
->inotify_source
);
277 dir
->inotify_source
= 0;
285 g_warning("dir_detach: Callback/data pair not attached!\n");
288 void dir_update(Directory
*dir
, gchar
*pathname
)
290 update(dir
, pathname
, NULL
);
293 /* Rescan this directory */
294 void refresh_dirs(const char *path
)
296 g_fscache_update(dir_cache
, path
);
299 /* When something has happened to a particular object, call this
300 * and all appropriate changes will be made.
302 void dir_check_this(const guchar
*path
)
308 dir_path
= g_path_get_dirname(path
);
309 real_path
= pathdup(dir_path
);
312 dir
= g_fscache_lookup_full(dir_cache
, real_path
,
313 FSCACHE_LOOKUP_PEEK
, NULL
);
316 dir_recheck(dir
, real_path
, g_basename(path
));
324 static void drop_notify(gpointer key
, gpointer value
, gpointer data
)
327 inotify_rm_watch(inotify_fd
, GPOINTER_TO_INT(key
));
330 close(GPOINTER_TO_INT(key
));
335 /* Used when we fork an action child, otherwise we can't delete or unmount
336 * any directory which we're watching via dnotify! inotify does not have
339 void dir_drop_all_notifies(void)
342 g_hash_table_foreach(notify_fd_to_dir
, drop_notify
, NULL
);
346 /* Tell watchers that this item has changed, but don't rescan.
347 * (used when thumbnail has been created for an item)
349 void dir_force_update_path(const gchar
*path
)
354 g_return_if_fail(path
[0] == '/');
356 dir_path
= g_path_get_dirname(path
);
358 dir
= g_fscache_lookup_full(dir_cache
, dir_path
, FSCACHE_LOOKUP_PEEK
,
362 dir_force_update_item(dir
, g_basename(path
));
369 /* Ensure that 'leafname' is up-to-date. Returns the new/updated
370 * DirItem, or NULL if the file no longer exists.
372 DirItem
*dir_update_item(Directory
*dir
, const gchar
*leafname
)
376 time(&diritem_recent_time
);
377 item
= insert_item(dir
, leafname
);
383 /* Add item to the recheck_list if it's marked as needing it.
384 * Item must have ITEM_FLAG_NEED_RESCAN_QUEUE.
385 * Items on the list will get checked later in an idle callback.
387 void dir_queue_recheck(Directory
*dir
, DirItem
*item
)
389 g_return_if_fail(dir
!= NULL
);
390 g_return_if_fail(item
!= NULL
);
391 g_return_if_fail(item
->flags
& ITEM_FLAG_NEED_RESCAN_QUEUE
);
393 dir
->recheck_list
= g_list_prepend(dir
->recheck_list
,
394 g_strdup(item
->leafname
));
395 item
->flags
&= ~ITEM_FLAG_NEED_RESCAN_QUEUE
;
398 static void free_recheck_list(Directory
*dir
)
400 destroy_glist(&dir
->recheck_list
);
403 /* If scanning state has changed then notify all filer windows */
404 static void dir_set_scanning(Directory
*dir
, gboolean scanning
)
408 if (scanning
== dir
->scanning
)
413 dir
->scanning
= scanning
;
415 for (next
= dir
->users
; next
; next
= next
->next
)
417 DirUser
*user
= (DirUser
*) next
->data
;
420 scanning
? DIR_START_SCAN
: DIR_END_SCAN
,
425 /* Useful for profiling */
436 /* Notify everyone that the error status of the directory has changed */
437 static void dir_error_changed(Directory
*dir
)
443 for (next
= dir
->users
; next
; next
= next
->next
)
445 DirUser
*user
= (DirUser
*) next
->data
;
447 user
->callback(dir
, DIR_ERROR_CHANGED
, NULL
, user
->data
);
453 /* This is called in the background when there are items on the
454 * dir->recheck_list to process.
456 static gboolean
recheck_callback(gpointer data
)
458 Directory
*dir
= (Directory
*) data
;
462 g_return_val_if_fail(dir
!= NULL
, FALSE
);
463 g_return_val_if_fail(dir
->recheck_list
!= NULL
, FALSE
);
465 /* Remove the first name from the list */
466 next
= dir
->recheck_list
;
467 dir
->recheck_list
= g_list_remove_link(dir
->recheck_list
, next
);
468 leaf
= (guchar
*) next
->data
;
473 insert_item(dir
, leaf
);
477 if (dir
->recheck_list
)
478 return TRUE
; /* Call again */
480 /* The recheck_list list empty. Stop scanning, unless
481 * needs_update, in which case we start scanning again.
486 dir
->have_scanned
= TRUE
;
487 dir_set_scanning(dir
, FALSE
);
488 g_source_remove(dir
->idle_callback
);
489 dir
->idle_callback
= 0;
491 if (dir
->needs_update
)
497 /* Add all the new items to the items array.
498 * Notify everyone who is watching us.
500 void dir_merge_new(Directory
*dir
)
502 GPtrArray
*new = dir
->new_items
;
503 GPtrArray
*up
= dir
->up_items
;
504 GPtrArray
*gone
= dir
->gone_items
;
510 for (list
= dir
->users
; list
; list
= list
->next
)
512 DirUser
*user
= (DirUser
*) list
->data
;
515 user
->callback(dir
, DIR_ADD
, new, user
->data
);
517 user
->callback(dir
, DIR_UPDATE
, up
, user
->data
);
519 user
->callback(dir
, DIR_REMOVE
, gone
, user
->data
);
524 for (i
= 0; i
< new->len
; i
++)
526 DirItem
*item
= (DirItem
*) new->pdata
[i
];
528 g_hash_table_insert(dir
->known_items
, item
->leafname
, item
);
531 for (i
= 0; i
< gone
->len
; i
++)
533 DirItem
*item
= (DirItem
*) gone
->pdata
[i
];
538 g_ptr_array_set_size(gone
, 0);
539 g_ptr_array_set_size(new, 0);
540 g_ptr_array_set_size(up
, 0);
544 /* Called from the mainloop shortly after dnotify_handler */
545 void dnotify_wakeup(void)
549 dnotify_wakeup_flag
= FALSE
;
551 dir
= g_hash_table_lookup(notify_fd_to_dir
,
552 GINT_TO_POINTER(dnotify_last_fd
));
555 dir_rescan_soon(dir
);
559 /****************************************************************
560 * INTERNAL FUNCTIONS *
561 ****************************************************************/
564 static gint
rescan_soon_timeout(gpointer data
)
566 Directory
*dir
= (Directory
*) data
;
568 dir
->rescan_timeout
= -1;
570 dir
->needs_update
= TRUE
;
576 /* Wait a fraction of a second and then rescan. If already waiting,
577 * this function does nothing.
579 static void dir_rescan_soon(Directory
*dir
)
581 if (dir
->rescan_timeout
!= -1)
583 dir
->rescan_timeout
= g_timeout_add(500, rescan_soon_timeout
, dir
);
587 static void free_items_array(GPtrArray
*array
)
591 for (i
= 0; i
< array
->len
; i
++)
593 DirItem
*item
= (DirItem
*) array
->pdata
[i
];
598 g_ptr_array_free(array
, TRUE
);
601 /* Tell everyone watching that these items have gone */
602 static void notify_deleted(Directory
*dir
, GPtrArray
*deleted
)
611 for (next
= dir
->users
; next
; next
= next
->next
)
613 DirUser
*user
= (DirUser
*) next
->data
;
615 user
->callback(dir
, DIR_REMOVE
, deleted
, user
->data
);
621 static void mark_unused(gpointer key
, gpointer value
, gpointer data
)
623 DirItem
*item
= (DirItem
*) value
;
625 item
->may_delete
= TRUE
;
628 static void keep_deleted(gpointer key
, gpointer value
, gpointer data
)
630 DirItem
*item
= (DirItem
*) value
;
631 GPtrArray
*deleted
= (GPtrArray
*) data
;
633 if (item
->may_delete
)
634 g_ptr_array_add(deleted
, item
);
637 static gboolean
check_unused(gpointer key
, gpointer value
, gpointer data
)
639 DirItem
*item
= (DirItem
*) value
;
641 return item
->may_delete
;
644 /* Remove all the old items that have gone.
645 * Notify everyone who is watching us of the removed items.
647 static void remove_missing(Directory
*dir
, GPtrArray
*keep
)
652 deleted
= g_ptr_array_new();
654 /* Mark all current items as may_delete */
655 g_hash_table_foreach(dir
->known_items
, mark_unused
, NULL
);
657 /* Unmark all items also in 'keep' */
658 for (i
= 0; i
< keep
->len
; i
++)
660 guchar
*leaf
= (guchar
*) keep
->pdata
[i
];
663 item
= g_hash_table_lookup(dir
->known_items
, leaf
);
666 item
->may_delete
= FALSE
;
669 /* Add each item still marked to 'deleted' */
670 g_hash_table_foreach(dir
->known_items
, keep_deleted
, deleted
);
672 /* Remove all items still marked */
673 g_hash_table_foreach_remove(dir
->known_items
, check_unused
, NULL
);
675 notify_deleted(dir
, deleted
);
677 free_items_array(deleted
);
680 static gint
notify_timeout(gpointer data
)
682 Directory
*dir
= (Directory
*) data
;
684 g_return_val_if_fail(dir
->notify_active
== TRUE
, FALSE
);
688 dir
->notify_active
= FALSE
;
694 /* Call dir_merge_new() after a while. */
695 static void delayed_notify(Directory
*dir
)
697 if (dir
->notify_active
)
700 g_timeout_add(1500, notify_timeout
, dir
);
701 dir
->notify_active
= TRUE
;
704 /* Stat this item and add, update or remove it.
705 * Returns the new/updated item, if any.
706 * (leafname may be from the current DirItem item)
707 * Ensure diritem_recent_time is reasonably up-to-date before calling this.
709 static DirItem
*insert_item(Directory
*dir
, const guchar
*leafname
)
711 const gchar
*full_path
;
714 gboolean do_compare
= FALSE
; /* (old is filled in) */
716 if (leafname
[0] == '.' && (leafname
[1] == '\n' ||
717 (leafname
[1] == '.' && leafname
[2] == '\n')))
718 return NULL
; /* Ignore '.' and '..' */
720 full_path
= make_path(dir
->pathname
, leafname
);
721 item
= g_hash_table_lookup(dir
->known_items
, leafname
);
725 if (item
->base_type
!= TYPE_UNKNOWN
)
727 /* Preserve the old details so we can compare */
730 g_object_ref(old
._image
);
733 diritem_restat(full_path
, item
, &dir
->stat_info
);
737 /* Item isn't already here. This won't normally happen,
738 * because blank items are added when scanning, before
741 item
= diritem_new(leafname
);
742 diritem_restat(full_path
, item
, &dir
->stat_info
);
743 if (item
->base_type
== TYPE_ERROR
&&
744 item
->lstat_errno
== ENOENT
)
749 g_ptr_array_add(dir
->new_items
, item
);
753 /* No need to queue the item for scanning. If we got here because
754 * the item was queued, this flag will normally already be clear.
756 item
->flags
&= ~ITEM_FLAG_NEED_RESCAN_QUEUE
;
758 if (item
->base_type
== TYPE_ERROR
&& item
->lstat_errno
== ENOENT
)
760 /* Item has been deleted */
761 g_hash_table_remove(dir
->known_items
, item
->leafname
);
762 g_ptr_array_add(dir
->gone_items
, item
);
763 if (do_compare
&& old
._image
)
764 g_object_unref(old
._image
);
771 /* It's a bit inefficient that we force the image to be
772 * loaded here, if we had an old image.
774 if (item
->lstat_errno
== old
.lstat_errno
775 && item
->base_type
== old
.base_type
776 && item
->flags
== old
.flags
777 && item
->size
== old
.size
778 && item
->mode
== old
.mode
779 && item
->atime
== old
.atime
780 && item
->ctime
== old
.ctime
781 && item
->mtime
== old
.mtime
782 && item
->uid
== old
.uid
783 && item
->gid
== old
.gid
784 && item
->mime_type
== old
.mime_type
785 && (old
._image
== NULL
|| di_image(item
) == old
._image
))
788 g_object_unref(old
._image
);
792 g_object_unref(old
._image
);
795 g_ptr_array_add(dir
->up_items
, item
);
801 static void update(Directory
*dir
, gchar
*pathname
, gpointer data
)
803 g_free(dir
->pathname
);
804 dir
->pathname
= pathdup(pathname
);
807 dir
->needs_update
= TRUE
;
812 /* If there is work to do, set the idle callback.
813 * Otherwise, stop scanning and unset the idle callback.
815 static void set_idle_callback(Directory
*dir
)
817 if (dir
->recheck_list
&& dir
->users
)
819 /* Work to do, and someone's watching */
820 dir_set_scanning(dir
, TRUE
);
821 if (dir
->idle_callback
)
823 time(&diritem_recent_time
);
824 dir
->idle_callback
= g_idle_add(recheck_callback
, dir
);
825 /* Do the first call now (will remove the callback itself) */
826 recheck_callback(dir
);
830 dir_set_scanning(dir
, FALSE
);
831 if (dir
->idle_callback
)
833 g_source_remove(dir
->idle_callback
);
834 dir
->idle_callback
= 0;
839 /* See dir_force_update_path() */
840 static void dir_force_update_item(Directory
*dir
, const gchar
*leaf
)
846 items
= g_ptr_array_new();
848 item
= g_hash_table_lookup(dir
->known_items
, leaf
);
852 g_ptr_array_add(items
, item
);
856 for (list
= dir
->users
; list
; list
= list
->next
)
858 DirUser
*user
= (DirUser
*) list
->data
;
860 user
->callback(dir
, DIR_UPDATE
, items
, user
->data
);
866 g_ptr_array_free(items
, TRUE
);
869 static void dir_recheck(Directory
*dir
,
870 const guchar
*path
, const guchar
*leafname
)
872 guchar
*old
= dir
->pathname
;
874 dir
->pathname
= g_strdup(path
);
877 time(&diritem_recent_time
);
878 insert_item(dir
, leafname
);
881 static void to_array(gpointer key
, gpointer value
, gpointer data
)
883 GPtrArray
*array
= (GPtrArray
*) data
;
885 g_ptr_array_add(array
, value
);
888 /* Convert a hash table to an unsorted GPtrArray.
889 * g_ptr_array_free() the result.
891 static GPtrArray
*hash_to_array(GHashTable
*hash
)
895 array
= g_ptr_array_new();
897 g_hash_table_foreach(hash
, to_array
, array
);
902 static gpointer parent_class
;
904 /* Note: dir_cache is never purged, so this shouldn't get called */
905 static void dir_finialize(GObject
*object
)
908 Directory
*dir
= (Directory
*) object
;
910 g_return_if_fail(dir
->users
== NULL
);
912 g_print("[ dir finalize ]\n");
914 free_recheck_list(dir
);
915 set_idle_callback(dir
);
916 if (dir
->rescan_timeout
!= -1)
917 g_source_remove(dir
->rescan_timeout
);
919 dir_merge_new(dir
); /* Ensures new, up and gone are empty */
921 g_ptr_array_free(dir
->up_items
, TRUE
);
922 g_ptr_array_free(dir
->new_items
, TRUE
);
923 g_ptr_array_free(dir
->gone_items
, TRUE
);
925 items
= hash_to_array(dir
->known_items
);
926 free_items_array(items
);
927 g_hash_table_destroy(dir
->known_items
);
930 g_free(dir
->pathname
);
932 G_OBJECT_CLASS(parent_class
)->finalize(object
);
935 static void directory_class_init(gpointer gclass
, gpointer data
)
937 GObjectClass
*object
= (GObjectClass
*) gclass
;
939 parent_class
= g_type_class_peek_parent(gclass
);
941 object
->finalize
= dir_finialize
;
944 static void directory_init(GTypeInstance
*object
, gpointer gclass
)
946 Directory
*dir
= (Directory
*) object
;
948 dir
->known_items
= g_hash_table_new(g_str_hash
, g_str_equal
);
949 dir
->recheck_list
= NULL
;
950 dir
->idle_callback
= 0;
951 dir
->scanning
= FALSE
;
952 dir
->have_scanned
= FALSE
;
955 dir
->needs_update
= TRUE
;
956 dir
->notify_active
= FALSE
;
957 dir
->pathname
= NULL
;
959 dir
->rescan_timeout
= -1;
964 dir
->inotify_source
= 0;
967 dir
->new_items
= g_ptr_array_new();
968 dir
->up_items
= g_ptr_array_new();
969 dir
->gone_items
= g_ptr_array_new();
972 static GType
dir_get_type(void)
974 static GType type
= 0;
978 static const GTypeInfo info
=
980 sizeof (DirectoryClass
),
981 NULL
, /* base_init */
982 NULL
, /* base_finalise */
983 directory_class_init
,
984 NULL
, /* class_finalise */
985 NULL
, /* class_data */
991 type
= g_type_register_static(G_TYPE_OBJECT
, "Directory",
998 static Directory
*dir_new(const char *pathname
)
1002 dir
= g_object_new(dir_get_type(), NULL
);
1004 dir
->pathname
= g_strdup(pathname
);
1009 /* Get the names of all files in the directory.
1010 * Remove any DirItems that are no longer listed.
1011 * Replace the recheck_list with the items found.
1013 static void dir_rescan(Directory
*dir
)
1019 const char *pathname
;
1022 g_return_if_fail(dir
!= NULL
);
1024 pathname
= dir
->pathname
;
1026 dir
->needs_update
= FALSE
;
1028 names
= g_ptr_array_new();
1031 mount_update(FALSE
);
1034 null_g_free(&dir
->error
);
1035 dir_error_changed(dir
);
1038 /* Saves statting the parent for each item... */
1039 if (mc_stat(pathname
, &dir
->stat_info
))
1041 dir
->error
= g_strdup_printf(_("Can't stat directory: %s"),
1043 dir_error_changed(dir
);
1044 return; /* Report on attach */
1047 d
= mc_opendir(pathname
);
1050 dir
->error
= g_strdup_printf(_("Can't open directory: %s"),
1052 dir_error_changed(dir
);
1053 return; /* Report on attach */
1056 dir_set_scanning(dir
, TRUE
);
1060 /* Make a list of all the names in the directory */
1061 while ((ent
= mc_readdir(d
)))
1063 if (ent
->d_name
[0] == '.')
1065 if (ent
->d_name
[1] == '\0')
1066 continue; /* Ignore '.' */
1067 if (ent
->d_name
[1] == '.' && ent
->d_name
[2] == '\0')
1068 continue; /* Ignore '..' */
1071 g_ptr_array_add(names
, g_strdup(ent
->d_name
));
1075 /* Compare the list with the current DirItems, removing
1076 * any that are missing.
1078 remove_missing(dir
, names
);
1080 free_recheck_list(dir
);
1082 /* For each name found, mark it as needing to be put on the rescan
1083 * list at some point in the future.
1084 * If the item is new, put a blank place-holder item in the directory.
1086 for (i
= 0; i
< names
->len
; i
++)
1089 guchar
*name
= names
->pdata
[i
];
1091 old
= g_hash_table_lookup(dir
->known_items
, name
);
1094 /* This flag is cleared when the item is added
1095 * to the rescan list.
1097 old
->flags
|= ITEM_FLAG_NEED_RESCAN_QUEUE
;
1103 new = diritem_new(name
);
1104 g_ptr_array_add(dir
->new_items
, new);
1111 /* Ask everyone which items they need to display, and add them to
1112 * the recheck list. Typically, this means we don't waste time
1113 * scanning hidden items.
1116 for (next
= dir
->users
; next
; next
= next
->next
)
1118 DirUser
*user
= (DirUser
*) next
->data
;
1120 DIR_QUEUE_INTERESTING
,
1125 g_ptr_array_free(names
, TRUE
);
1127 set_idle_callback(dir
);
1132 /* Signal handler - don't do anything dangerous here */
1133 static void dnotify_handler(int sig
, siginfo_t
*si
, void *data
)
1135 /* Note: there is currently only one place to store the fd,
1136 * so we'll miss updates to several directories if they happen
1139 dnotify_last_fd
= si
->si_fd
;
1140 dnotify_wakeup_flag
= TRUE
;
1141 write(to_wakeup_pipe
, "\0", 1); /* Wake up! */
1146 static gboolean
inotify_handler(GIOChannel
*source
, GIOCondition condition
,
1149 int fd
= g_io_channel_unix_get_fd(source
);
1151 char buf
[sizeof(struct inotify_event
)+1024];
1154 len
= read(fd
, buf
, sizeof(buf
));
1166 struct inotify_event
*event
=(struct inotify_event
*) (buf
+i
);
1168 dir
= g_hash_table_lookup(notify_fd_to_dir
,
1169 GINT_TO_POINTER(event
->wd
));
1171 dir_rescan_soon(dir
);
1173 i
+= sizeof(*event
)+event
->len
;