static CachedDir *
cached_dir_add_subdir (CachedDir  *dir,
                       const char *basename,
                       const char *path)
{
  CachedDir *subdir;

  subdir = find_subdir (dir, basename);

  if (subdir != NULL)
    {
      subdir->deleted = FALSE;
      return subdir;
    }

  subdir = cached_dir_new (basename);

  if (path != NULL && !cached_dir_load_entries_recursive (subdir, path))
    {
      cached_dir_free (subdir);
      return NULL;
    }

  menu_verbose ("Caching dir \"%s\"\n", basename);

  subdir->parent = dir;
  dir->subdirs = g_slist_prepend (dir->subdirs, cached_dir_ref (subdir));

  return subdir;
}
static void
cached_dir_unref_noparent (CachedDir *dir)
{
  if (--dir->references == 0)
    {
      if (dir->notify)
        dir->notify (dir, dir->notify_data);

      cached_dir_free (dir);
    }
}
static void
cached_dir_unref (CachedDir *dir)
{
  if (--dir->references == 0)
    {
      CachedDir *parent;

      parent = dir->parent;

      if (parent != NULL)
        cached_dir_remove_subdir (parent, dir->name);

      if (dir->notify)
        dir->notify (dir, dir->notify_data);

      cached_dir_free (dir);
    }
}
static void
cached_dir_unref (CachedDir *dir)
{
  gboolean is_zero;

  is_zero = g_atomic_int_dec_and_test (&dir->references);
  if (is_zero)
    {
      CachedDir *parent;

      parent = dir->parent;

      if (parent != NULL)
        cached_dir_remove_subdir (parent, dir->name);

      if (dir->notify)
        dir->notify (dir, dir->notify_data);

      cached_dir_free (dir);
    }
}
static gboolean
cached_dir_remove_subdir (CachedDir  *dir,
                          const char *basename)
{
  CachedDir *subdir;

  subdir = find_subdir (dir, basename);

  if (subdir != NULL)
    {
      subdir->deleted = TRUE;

      if (subdir->references == 0)
        {
          cached_dir_free (subdir);
          dir->subdirs = g_slist_remove (dir->subdirs, subdir);
        }

      return TRUE;
    }

  return FALSE;
}
static void
cached_dir_remove_reference (CachedDir *dir)
{
  CachedDir *parent;

  parent = dir->parent;

  if (--dir->references == 0 && dir->deleted)
    {
      if (dir->parent != NULL)
	{
	  GSList *tmp;

	  tmp = parent->subdirs;
	  while (tmp != NULL)
	    {
	      CachedDir *subdir = tmp->data;

	      if (!strcmp (subdir->name, dir->name))
		{
		  parent->subdirs = g_slist_delete_link (parent->subdirs, tmp);
		  break;
		}

	      tmp = tmp->next;
	    }
	}

      cached_dir_free (dir);
    }

  if (parent != NULL)
    {
      cached_dir_remove_reference (parent);
    }
}