Skip to content

Instantly share code, notes, and snippets.

@dmatveev
Created June 20, 2011 20:53
Show Gist options
  • Save dmatveev/1036558 to your computer and use it in GitHub Desktop.
Save dmatveev/1036558 to your computer and use it in GitHub Desktop.
Directory tree activity monitor
#include <glib.h>
#include <gio/gio.h>
#include <glib/gstdio.h>
#include <sys/resource.h>
static GHashTable *g_all_entries = NULL;
G_GNUC_INTERNAL G_LOCK_DEFINE (hash_lock);
static void
on_file_change (GFileMonitor *, GFile *, GFile *, GFileMonitorEvent, gpointer);
static void
add_file (const gchar *path);
static void
add_tree (const gchar *path);
static void
add_if_directory(const gchar *path);
static void
add_if_directory(const gchar *path)
{
GFile *file = g_file_new_for_path (path);
if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
add_tree (path);
g_object_unref (file);
}
static void
cancel_on_delete (GFileMonitor *mon, const gchar *path)
{
g_file_monitor_cancel(mon);
G_LOCK (hash_lock);
g_hash_table_remove (g_all_entries, path);
G_UNLOCK (hash_lock);
}
#define pcase(sym, file, code) \
case G_FILE_MONITOR_EVENT_##sym: \
g_print (#sym": %s\n", file); \
{code;}; \
break
static void
on_file_change (GFileMonitor *mon,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
gchar *path = g_file_get_path (file);
switch (event_type)
{
pcase(CHANGED, path, add_if_directory(path));
pcase(CHANGES_DONE_HINT, path, {});
pcase(DELETED, path, cancel_on_delete(mon, path));
pcase(CREATED, path, {});
pcase(ATTRIBUTE_CHANGED, path, {});
pcase(PRE_UNMOUNT, path, {});
pcase(UNMOUNTED, path, {});
pcase(MOVED, path, {});
default:
g_print ("What?\n");
}
g_free (path);
}
static void
add_file (const gchar *path)
{
GFile *file = g_file_new_for_path (path);
G_LOCK (hash_lock);
if (!g_hash_table_lookup (g_all_entries, path)) {
GFileMonitor *mon;
g_hash_table_insert (g_all_entries, (gpointer) g_strdup(path), GINT_TO_POINTER(TRUE));
mon = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_signal_connect (mon, "changed", G_CALLBACK(on_file_change), NULL);
}
G_UNLOCK (hash_lock);
}
static void
add_tree (const gchar *path)
{
GDir *root = NULL;
const gchar *each = NULL;
root = g_dir_open (path, 0, NULL);
if (root == NULL)
return;
while (each = g_dir_read_name (root))
{
gchar *full = g_strconcat (path, "/", each, NULL);
GFile *file = g_file_new_for_path (full);
if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_DIRECTORY)
add_tree (full);
else
add_file (full);
g_object_unref (file);
g_free (full);
}
/* yes, add_file() is also fine to start monitoring on a directory */
add_file (path);
g_dir_close (root);
}
int
main (int argc, char *argv[])
{
GMainLoop *loop;
struct rlimit rl;
rl.rlim_cur = 3072;
rl.rlim_max = 10240;
setrlimit (RLIMIT_NOFILE, &rl);
if (argc < 2)
return 1;
g_type_init();
g_all_entries = g_hash_table_new_full (g_str_hash,
g_str_equal,
(GDestroyNotify) g_free,
NULL);
add_tree (argv[1]);
g_print ("READY!\n");
loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (loop);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment