gnome-commander r2479 - in branches/gcmd-1-3: . doc/C src



Author: epiotr
Date: Tue Feb 24 18:07:57 2009
New Revision: 2479
URL: http://svn.gnome.org/viewvc/gnome-commander?rev=2479&view=rev

Log:
Fixed problem #567506 (slow startup for systems with many users)

Modified:
   branches/gcmd-1-3/ChangeLog
   branches/gcmd-1-3/NEWS
   branches/gcmd-1-3/doc/C/gnome-commander.xml
   branches/gcmd-1-3/src/gnome-cmd-chown-component.cc
   branches/gcmd-1-3/src/gnome-cmd-chown-dialog.cc
   branches/gcmd-1-3/src/gnome-cmd-file.cc
   branches/gcmd-1-3/src/gnome-cmd-main-win.cc
   branches/gcmd-1-3/src/main.cc
   branches/gcmd-1-3/src/owner.cc
   branches/gcmd-1-3/src/owner.h

Modified: branches/gcmd-1-3/NEWS
==============================================================================
--- branches/gcmd-1-3/NEWS	(original)
+++ branches/gcmd-1-3/NEWS	Tue Feb 24 18:07:57 2009
@@ -11,6 +11,7 @@
  * Fixed problem #554598 (GNOME Goal: LINGUAS)
  * Fixed problem #556664 (bookmarks can not be saved for mounted devices)
  * Fixed problem #567404 (crash when INSERT pressed over subdir)
+ * Fixed problem #567506 (slow startup for systems with many users)
  * Fixed problem #570727 (usage of deprecated gnome_url_show)
  * Fixed problem #571239 (replacing obsoleted GnomeColorPicker with GtkColorButton)
  * Fixed problem #571247 (replacing obsoleted GnomePixmap with GtkImage)

Modified: branches/gcmd-1-3/doc/C/gnome-commander.xml
==============================================================================
--- branches/gcmd-1-3/doc/C/gnome-commander.xml	(original)
+++ branches/gcmd-1-3/doc/C/gnome-commander.xml	Tue Feb 24 18:07:57 2009
@@ -5894,6 +5894,9 @@
                             <para>Fixed problem #567404 (crash when INSERT pressed over subdir)</para>
                         </listitem>
                         <listitem>
+                            <para>Fixed problem #567506 (slow startup for systems with many users)</para>
+                        </listitem>
+                        <listitem>
                             <para>Fixed problem #570727 (usage of deprecated gnome_url_show)</para>
                         </listitem>
                         <listitem>

Modified: branches/gcmd-1-3/src/gnome-cmd-chown-component.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-chown-component.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-chown-component.cc	Tue Feb 24 18:07:57 2009
@@ -32,7 +32,6 @@
 struct _GnomeCmdChownComponentPrivate
 {
     GtkWidget *user_combo, *group_combo;
-    GList *user_strings, *group_strings;
 };
 
 
@@ -100,36 +99,19 @@
  * Public functions
  ***********************************/
 
-static void load_users_and_groups (GnomeCmdChownComponent *comp)
+inline void load_users_and_groups (GnomeCmdChownComponent *comp)
 {
-    user_t *prog_user = OWNER_get_program_user ();
-
-    g_return_if_fail (prog_user != NULL);
-
     // disable user combo if user is not root, else fill the combo with all users in the system
-    if (prog_user->uid != 0)
-        gtk_widget_set_sensitive (comp->priv->user_combo, FALSE);
+    if (gcmd_owner.is_root())
+        gtk_combo_set_popdown_strings (GTK_COMBO (comp->priv->user_combo), gcmd_owner.users.get_names());
     else
-    {
-        for (GList *tmp = OWNER_get_all_users (); tmp; tmp = tmp->next)
-        {
-            user_t *user = (user_t *) tmp->data;
-
-            comp->priv->user_strings = g_list_append (comp->priv->user_strings, g_strdup (user->name));
-        }
-
-        gtk_combo_set_popdown_strings (GTK_COMBO (comp->priv->user_combo), comp->priv->user_strings);
-    }
-
-    // fill the groups combo with all groups that the user is part of if ordinary user or all groups if root
-
-    for (GList *tmp = prog_user->uid != 0 ? prog_user->groups : OWNER_get_all_groups (); tmp; tmp = tmp->next)
-    {
-        group_t *group = (group_t *) tmp->data;
-        comp->priv->group_strings = g_list_append (comp->priv->group_strings, g_strdup (group->name));
-    }
+        gtk_widget_set_sensitive (comp->priv->user_combo, FALSE);
 
-    gtk_combo_set_popdown_strings (GTK_COMBO (comp->priv->group_combo), comp->priv->group_strings);
+    if (gcmd_owner.get_group_names())
+        gtk_combo_set_popdown_strings (GTK_COMBO (comp->priv->group_combo), gcmd_owner.get_group_names());      // fill the groups combo with all groups that the user is part of
+                                                                                                                // if ordinary user or all groups if root
+    else
+        gtk_widget_set_sensitive (comp->priv->group_combo, FALSE);                                              // disable group combo if yet not loaded
 }
 
 
@@ -167,27 +149,24 @@
 }
 
 
-void gnome_cmd_chown_component_set (GnomeCmdChownComponent *comp, uid_t owner, gid_t group)
+void gnome_cmd_chown_component_set (GnomeCmdChownComponent *comp, uid_t uid, gid_t gid)
 {
-    const gchar *s_owner = OWNER_get_name_by_uid (owner);
-    const gchar *s_group = OWNER_get_name_by_gid (group);
-
-    gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (comp->priv->user_combo)->entry), s_owner);
-    gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (comp->priv->group_combo)->entry), s_group);
+    gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (comp->priv->user_combo)->entry), gcmd_owner.users[uid]);
+    gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (comp->priv->group_combo)->entry), gcmd_owner.groups[gid]);
 }
 
 
 uid_t gnome_cmd_chown_component_get_owner (GnomeCmdChownComponent *component)
 {
-    const gchar *s_owner = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (component->priv->user_combo)->entry));
+    const gchar *owner = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (component->priv->user_combo)->entry));
 
-    return OWNER_get_uid_by_name (s_owner);
+    return gcmd_owner.users[owner];
 }
 
 
 gid_t gnome_cmd_chown_component_get_group (GnomeCmdChownComponent *component)
 {
-    const gchar *s_group = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (component->priv->group_combo)->entry));
+    const gchar *group = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (component->priv->group_combo)->entry));
 
-    return OWNER_get_gid_by_name (s_group);
+    return gcmd_owner.groups[group];
 }

Modified: branches/gcmd-1-3/src/gnome-cmd-chown-dialog.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-chown-dialog.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-chown-dialog.cc	Tue Feb 24 18:07:57 2009
@@ -91,21 +91,17 @@
 {
     uid_t uid = -1;
     gid_t gid = -1;
-    user_t *user = OWNER_get_program_user();
-    gboolean recurse;
 
-    if (user && user->uid == 0)
+    if (gcmd_owner.is_root())
     {
-        uid = gnome_cmd_chown_component_get_owner (
-            GNOME_CMD_CHOWN_COMPONENT (dialog->priv->chown_component));
+        uid = gnome_cmd_chown_component_get_owner (GNOME_CMD_CHOWN_COMPONENT (dialog->priv->chown_component));
         g_return_if_fail (uid >= 0);
     }
 
-    gid = gnome_cmd_chown_component_get_group (
-        GNOME_CMD_CHOWN_COMPONENT (dialog->priv->chown_component));
+    gid = gnome_cmd_chown_component_get_group (GNOME_CMD_CHOWN_COMPONENT (dialog->priv->chown_component));
     g_return_if_fail (gid >= 0);
 
-    recurse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->recurse_check));
+    gboolean recurse = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (dialog->priv->recurse_check));
 
     for (GList *tmp = dialog->priv->files; tmp; tmp = tmp->next)
     {

Modified: branches/gcmd-1-3/src/gnome-cmd-file.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-file.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-file.cc	Tue Feb 24 18:07:57 2009
@@ -473,7 +473,7 @@
     g_return_val_if_fail (file->info != NULL, NULL);
 
     if (GNOME_VFS_FILE_INFO_LOCAL (file->info))
-        return OWNER_get_name_by_uid (file->info->uid);
+        return gcmd_owner.get_name_by_uid(file->info->uid);
     else
     {
         static gchar owner_str[MAX_OWNER_LENGTH];
@@ -489,7 +489,7 @@
     g_return_val_if_fail (file->info != NULL, NULL);
 
     if (GNOME_VFS_FILE_INFO_LOCAL (file->info))
-        return OWNER_get_name_by_gid (file->info->gid);
+        return gcmd_owner.get_name_by_gid(file->info->gid);
     else
     {
         static gchar group_str[MAX_GROUP_LENGTH];
@@ -849,15 +849,11 @@
     if (!gnome_cmd_file_is_local (f))
         return FALSE;
 
-    user_t *user = OWNER_get_program_user ();
-    if (!user)
-        return FALSE;
-
-    if (user->uid == f->info->uid
+    if (gcmd_owner.uid() == f->info->uid
         && f->info->permissions & GNOME_VFS_PERM_USER_EXEC)
         return TRUE;
 
-    if (user->gid == f->info->gid
+    if (gcmd_owner.gid() == f->info->gid
         && f->info->permissions & GNOME_VFS_PERM_GROUP_EXEC)
         return TRUE;
 

Modified: branches/gcmd-1-3/src/gnome-cmd-main-win.cc
==============================================================================
--- branches/gcmd-1-3/src/gnome-cmd-main-win.cc	(original)
+++ branches/gcmd-1-3/src/gnome-cmd-main-win.cc	Tue Feb 24 18:07:57 2009
@@ -37,6 +37,7 @@
 #include "gnome-cmd-con.h"
 #include "gnome-cmd-con-list.h"
 #include "gnome-cmd-bookmark-dialog.h"
+#include "owner.h"
 #include "utils.h"
 
 #include "../pixmaps/copy_file_names.xpm"
@@ -771,8 +772,8 @@
     mw->priv->file_selector[LEFT] = NULL;
     mw->priv->file_selector[RIGHT] = NULL;
 
-    gnome_app_construct (GNOME_APP (main_win), "gnome-commander", geteuid() ? _("GNOME Commander") :
-                                                                              _("GNOME Commander - ROOT PRIVILEGES"));
+    gnome_app_construct (GNOME_APP (main_win), "gnome-commander", gcmd_owner.is_root() ? _("GNOME Commander - ROOT PRIVILEGES") :
+                                                                                         _("GNOME Commander"));
     gtk_object_set_data (GTK_OBJECT (main_win), "main_win", main_win);
     restore_size_and_pos (mw);
     gtk_window_set_policy (GTK_WINDOW (main_win), TRUE, TRUE, FALSE);

Modified: branches/gcmd-1-3/src/main.cc
==============================================================================
--- branches/gcmd-1-3/src/main.cc	(original)
+++ branches/gcmd-1-3/src/main.cc	Tue Feb 24 18:07:57 2009
@@ -130,12 +130,12 @@
         gnome_cmd_smb_auth_init ();
 
     gnome_cmd_style_create ();
-    OWNER_init ();
     gcmd_user_actions.init();
 
     main_win_widget = gnome_cmd_main_win_new ();
     main_win = GNOME_CMD_MAIN_WIN (main_win_widget);
     gtk_widget_show (GTK_WIDGET (main_win));
+    gcmd_owner.load_async();
 
     gcmd_tags_init();
     plugin_manager_init ();
@@ -153,7 +153,6 @@
     gcmd_user_actions.shutdown();
     gnome_cmd_data.save();
     gnome_vfs_shutdown ();
-    OWNER_free ();
     IMAGE_free ();
 
     remove_temp_download_dir ();

Modified: branches/gcmd-1-3/src/owner.cc
==============================================================================
--- branches/gcmd-1-3/src/owner.cc	(original)
+++ branches/gcmd-1-3/src/owner.cc	Tue Feb 24 18:07:57 2009
@@ -18,6 +18,11 @@
     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
 */
 
+#include <unistd.h>
+
+#include <map>
+#include <set>
+
 #include <config.h>
 #include "gnome-cmd-includes.h"
 #include "owner.h"
@@ -26,302 +31,107 @@
 using namespace std;
 
 
-GList *all_users;
-GList *all_groups;
+GnomeCmdOwner gcmd_owner;
 
 
-static gint compare_users (user_t *u1, user_t *u2)
+static gint compare_names (const gchar *name1, const gchar *name2)
 {
-    return strcmp (u1->name, u2->name);
+    return strcmp(name1, name2);
 }
 
 
-static gint compare_groups (user_t *g1, user_t *g2)
+#if !GLIB_CHECK_VERSION (2, 14, 0)
+template <typename T, typename ID>
+GList *GnomeCmdOwner::HashTable<T,ID>::get_names()
 {
-    return strcmp (g1->name, g2->name);
-}
-
-
-inline user_t *create_user (struct passwd *pw, gboolean zombie)
-{
-    if (pw)
-    {
-        user_t *user = g_new0 (user_t, 1);
+    GList *retval = NULL;
 
-        user->zombie =   zombie;
-        user->name =     g_strdup (pw->pw_name);
-        user->uid =      pw->pw_uid;
-        user->gid =      pw->pw_gid;
-        user->realname = g_strdup (pw->pw_gecos);
-        // user->groups =   NULL; // filled in later when going through the group members
+    for (GList *l=users; l; l=l->next)
+        retval = g_list_prepend (retval, static_cast<user_t *>(l->data)->name);
 
-        return user;
-    }
-
-    return NULL;
+    return g_list_sort (retval, (GCompareFunc) compare_users);
 }
+#endif
 
 
-static group_t *create_group (struct group *gr, gboolean zombie)
+GnomeCmdOwner::GnomeCmdOwner()
 {
-    group_t *group = NULL;
+    thread = NULL;
+    stop_thread = FALSE;
+    group_names = NULL;
 
-    if (gr)
+    if (!buff)
     {
-        group = g_new0 (group_t, 1);
-
-        group->zombie =  zombie;
-        group->name =    g_strdup (gr->gr_name);
-        group->gid =     gr->gr_gid;
-        // group->members = NULL;
-
-        char **members = gr->gr_mem;
-
-        while (members && *members)
-        {
-            user_t *user = OWNER_get_user_by_name (*members);
-
-            if (user)
-            {
-                group->members = g_list_append (group->members, user);
-                user->groups = g_list_append (user->groups, group);
-            }
-            else
-                g_printerr (_("When parsing the users and groups on this system it was found that the user %s is part of the group %s. This user can however not be found.\n"), *members, group->name);
-
-            members++;
-        }
+        buffsize = max(sysconf(_SC_GETPW_R_SIZE_MAX), sysconf(_SC_GETGR_R_SIZE_MAX));
+        buff = g_new0 (char, buffsize);
     }
 
-    return group;
-}
-
-
-inline void free_user (user_t *user)
-{
-    g_free (user->name);
-    g_free (user->realname);
-    g_free (user);
-}
-
-
-inline void free_group (group_t *group)
-{
-    g_free (group->name);
-    g_list_free (group->members);
-    g_free (group);
-}
-
-
-inline void lookup_all_users ()
-{
-    struct passwd *pw;
-
-    setpwent ();
-
-    while ((pw = getpwent ()) != NULL)
-        all_users = g_list_prepend (all_users, create_user (pw, FALSE));
-
-    endpwent ();
-
-    all_users = g_list_sort (all_users, (GCompareFunc) compare_users);
+    user_id = geteuid();
+    get_name_by_uid(user_id);
+    group_id = users.lookup(user_id)->data.gid;
 }
 
 
-inline void lookup_all_groups ()
+gpointer GnomeCmdOwner::perform_load_operation (GnomeCmdOwner *self)
 {
-    struct group *gr;
+    map <uid_t, set<gid_t> > user_groups;
+    map <gid_t, set<uid_t> > group_members;
 
-    setgrent ();
+    setpwent();
 
-    while ((gr = getgrent ()) != NULL)
-        all_groups = g_list_prepend (all_groups, create_group (gr, FALSE));
+    for (struct passwd *pwd=getpwent(); !self->stop_thread && pwd; pwd=getpwent())
+    {
+        GnomeCmdUsers::Entry *e = self->users.lookup(pwd->pw_uid);
 
-    endgrent ();
+        if (!e)
+            e = self->new_entry(pwd);
 
-    all_groups = g_list_sort (all_groups, (GCompareFunc) compare_groups);
-}
+        user_groups[e->id].insert(e->data.gid);
+        group_members[e->data.gid].insert(e->id);
+    }
 
+    endpwent();
 
-inline void check_user_default_groups ()
-{
-    user_t *user;
-    group_t *group;
+    setgrent();
 
-    for (GList *utmp=all_users; utmp; utmp=utmp->next)
+    for (struct group *grp=getgrent(); !self->stop_thread && grp; grp=getgrent())
     {
-        group_t *def_group = NULL;
-        user = (user_t *) utmp->data;
+        if (!self->groups.lookup(grp->gr_gid))
+            self->new_entry(grp);
 
-        for (GList *gtmp=user->groups; gtmp; gtmp=gtmp->next)
+        for (char **mem=grp->gr_mem; *mem; ++mem)
         {
-            group = (group_t *) gtmp->data;
+            GnomeCmdUsers::Entry *e = self->users.lookup(*mem);
 
-            if (group->gid == user->gid)
+            if (e)
             {
-                def_group = group;
-                break;
+                user_groups[e->id].insert(grp->gr_gid);
+                group_members[grp->gr_gid].insert(e->id);
             }
         }
-
-        if (!def_group)
-        {
-            def_group = OWNER_get_group_by_gid (user->gid);
-            user->groups = g_list_append (user->groups, def_group);
-
-            def_group->members = g_list_append (def_group->members, user);
-        }
     }
-}
-
 
-/************************************************************************/
-
-
-user_t *OWNER_get_user_by_uid (uid_t uid)
-{
-    user_t *user;
+    endgrent();
 
-    // try to locate the user in the list of already found users
-    for (GList *tmp = all_users; tmp; tmp = tmp->next)
+    if (!self->is_root())
     {
-        user = (user_t *) tmp->data;
+        map <uid_t, set<gid_t> >::iterator x = user_groups.find(self->uid());
 
-        if (uid == user->uid)
-            return user;
+        if (x!=user_groups.end())
+            for (set<gid_t>::const_iterator i=x->second.begin(); i!=x->second.end(); ++i)
+                self->group_names = g_list_prepend (self->group_names, (gpointer) self->groups[*i]);
     }
+    else
+        for (map <gid_t, set<uid_t> >::const_iterator i=group_members.begin(); i!=group_members.end(); ++i)
+            self->group_names = g_list_prepend (self->group_names, (gpointer) self->groups[i->first]);
 
-    // there is no such user in the system, lets create a blank user with the specified uid
-
-    struct passwd pw;
-
-    pw.pw_uid = uid;
-    pw.pw_name = g_strdup_printf ("%d", uid);
-    pw.pw_gecos = "";
-    pw.pw_dir = "";
-    pw.pw_shell = "";
-    pw.pw_passwd = "";
-
-    user = create_user (&pw, TRUE);
-    if (user)
-        all_users = g_list_append (all_users, user);
-
-    g_free (pw.pw_name);
-
-    return user;
-}
-
-
-user_t *OWNER_get_user_by_name (const char *name)
-{
-    // try to locate the user in the list of already found users
-    for (GList *tmp = all_users; tmp; tmp = tmp->next)
-    {
-        user_t *user = (user_t *) tmp->data;
-
-        if (strcmp (name, user->name) == 0)
-            return user;
-    }
-
-    return NULL;
-}
-
-
-group_t *OWNER_get_group_by_gid (gid_t gid)
-{
-    // try to locate the group in the list of already found groups
-    for (GList *tmp = all_groups; tmp; tmp = tmp->next)
-    {
-        group_t *group = (group_t *) tmp->data;
-
-        if (gid == group->gid)
-            return group;
-    }
-
-    // there is no such group in the system, lets create a blank group with the specified gid
-    struct group gr;
-
-    gr.gr_gid = gid;
-    gr.gr_name = g_strdup_printf ("%d", gid);
-    gr.gr_passwd = "";
-    gr.gr_mem = NULL;
-
-    group_t *group = create_group (&gr, TRUE);
-    if (group)
-        all_groups = g_list_append (all_groups, group);
-
-    g_free (gr.gr_name);
-
-    return group;
-}
-
-
-group_t *OWNER_get_group_by_name (const char *name)
-{
-    // try to locate the group in the list of already found groups
-    for (GList *tmp = all_groups; tmp; tmp = tmp->next)
-    {
-        group_t *group = (group_t *) tmp->data;
-
-        if (strcmp (name, group->name) == 0)
-            return group;
-    }
+    self->group_names = g_list_sort (self->group_names, (GCompareFunc) compare_names); ;
 
     return NULL;
 }
 
 
-void OWNER_init ()
-{
-    all_users = NULL;
-    all_groups = NULL;
-
-    lookup_all_users ();
-    lookup_all_groups ();
-    check_user_default_groups ();
-}
-
-
-void OWNER_free ()
-{
-
-    /* free users */
-    for (GList *users=all_users; users; users=users->next)
-    {
-        user_t *user = (user_t *) users->data;
-        free_user (user);
-    }
-
-    /* free groups */
-    for (GList *groups=all_groups; groups; groups=groups->next)
-    {
-        group_t *group = (group_t *) groups->data;
-        free_group (group);
-    }
-
-    g_list_free (all_users);
-    g_list_free (all_groups);
-}
-
-
-user_t *OWNER_get_program_user ()
-{
-    const char *name = g_get_user_name ();
-    user_t *user = OWNER_get_user_by_name (name);
-
-    g_assert (user);
-
-    return user;
-}
-
-
-GList *OWNER_get_all_users ()
-{
-    return all_users;
-}
-
-
-GList *OWNER_get_all_groups ()
+void GnomeCmdOwner::load_async()
 {
-    return all_groups;
+    thread = g_thread_create ((GThreadFunc) perform_load_operation, this, TRUE, NULL);
 }

Modified: branches/gcmd-1-3/src/owner.h
==============================================================================
--- branches/gcmd-1-3/src/owner.h	(original)
+++ branches/gcmd-1-3/src/owner.h	Tue Feb 24 18:07:57 2009
@@ -24,64 +24,249 @@
 #include <grp.h>
 #include <pwd.h>
 
-struct group_t
+class GnomeCmdOwner
 {
-    char *name;
-    gid_t gid;
-    GList *members;     // stores the members as char *strings
-    gboolean zombie;    // The gid of this group doesn't match any group in the system
+    GThread *thread;
+    gboolean stop_thread;
+    char *buff;
+    size_t buffsize;
+
+    uid_t user_id;
+    gid_t group_id;
+
+    GList *group_names;
+
+  public:
+
+    template <typename T, typename ID>
+    class HashTable
+    {
+        GHashTable *id_table;
+        GHashTable *name_table;
+
+        GList *entries;
+
+        struct Entry
+        {
+            ID id;
+            char *name;
+            T  data;
+        };
+
+        Entry *lookup(ID id)                    {  return (Entry *) g_hash_table_lookup (id_table, &id);      }
+        Entry *lookup(const gchar *name)        {  return (Entry *) g_hash_table_lookup (name_table, name);   }
+        Entry *add(ID id, const gchar *name);
+
+      public:
+
+        HashTable();
+        ~HashTable();
+
+        guint size()                            {  return g_hash_table_size (id_table);  }
+        gboolean empty()                        {  return size()==0;                     }
+
+        const gchar *operator [] (ID id);
+        ID operator [] (const gchar *name);
+        GList *get_names();
+
+        friend class GnomeCmdOwner;
+    };
+
+    struct user_t
+    {
+        char *real_name;
+        gid_t gid;
+        gboolean zombie;    // the uid of this user doesn't match any user in the system
+    };
+
+    struct group_t
+    {
+        gboolean zombie;    // the gid of this group doesn't match any group in the system
+    };
+
+    typedef HashTable<user_t,uid_t> GnomeCmdUsers;
+    typedef HashTable<group_t,gid_t> GnomeCmdGroups;
+
+  private:
+
+    GnomeCmdUsers::Entry *new_entry(const struct passwd *pw);
+    GnomeCmdGroups::Entry *new_entry(const struct group *grp);
+
+    static gpointer perform_load_operation (GnomeCmdOwner *self);
+
+  public:
+
+    GnomeCmdUsers users;
+    GnomeCmdGroups groups;
+
+    GnomeCmdOwner();
+    ~GnomeCmdOwner();
+
+    uid_t uid() const           {  return user_id;   }
+    gid_t gid() const           {  return group_id;  }
+    gboolean is_root()          {  return uid()==0;  }
+
+    GList *get_group_names()    {  return group_names;  }
+
+    const char *get_name_by_uid(uid_t uid);
+    const char *get_name_by_gid(gid_t gid);
+
+   void load_async();
 };
 
-struct user_t
+template <typename T, typename ID>
+inline GnomeCmdOwner::HashTable<T,ID>::HashTable()
 {
-    char *name;
-    uid_t uid;
-    gid_t gid;
-    group_t *group;
-    char *realname;
-    GList *groups;
-    gboolean zombie;    // The uid of this user doesn't match any user in the system
-};
+    entries = NULL;
+    id_table = g_hash_table_new (g_int_hash, g_int_equal);
+    name_table = g_hash_table_new (g_str_hash, g_str_equal);
+}
 
-void OWNER_init ();
-void OWNER_free ();
-user_t *OWNER_get_program_user ();
-user_t *OWNER_get_user_by_uid (uid_t uid);
-group_t *OWNER_get_group_by_gid (gid_t gid);
-user_t *OWNER_get_user_by_name (const char *name);
-group_t *OWNER_get_group_by_name (const char *name);
-GList *OWNER_get_all_users ();
-GList *OWNER_get_all_groups ();
+template <typename T, typename ID>
+inline GnomeCmdOwner::HashTable<T,ID>::~HashTable()
+{
+    g_hash_table_destroy (id_table);
+    g_hash_table_destroy (name_table);
+    if (entries)
+    {
+        g_list_foreach (entries, (GFunc) g_free, NULL);
+        g_list_free (entries);
+    }
+}
 
-inline const gchar *OWNER_get_name_by_uid (uid_t uid)
+template <typename T, typename ID>
+inline typename GnomeCmdOwner::HashTable<T,ID>::Entry *GnomeCmdOwner::HashTable<T,ID>::add(ID id, const gchar *name)
 {
-    user_t *user = OWNER_get_user_by_uid (uid);
+    Entry *e = g_new0 (Entry, 1);
+
+    e->id = id;
+    e->name = g_strdup (name);
+
+    entries = g_list_prepend (entries, e);
 
-    return user ? user->name : NULL;
+    g_hash_table_insert (id_table, &e->id, e);
+    g_hash_table_insert (name_table, e->name, e);
+
+    return e;
 }
 
+template <typename T, typename ID>
+inline const gchar *GnomeCmdOwner::HashTable<T,ID>::operator [] (ID id)
+{
+    Entry *entry = lookup(id);
+
+    g_assert (entry != NULL);
 
-inline const gchar *OWNER_get_name_by_gid (gid_t gid)
+    return entry ? entry->name : NULL;
+}
+
+template <typename T, typename ID>
+inline ID GnomeCmdOwner::HashTable<T,ID>::operator [] (const gchar *name)
 {
-    group_t *group = OWNER_get_group_by_gid (gid);
+    Entry *entry = lookup(name);
+
+    g_assert (entry != NULL);
 
-    return group ? group->name : NULL;
+    return entry ? entry->id : -1;
 }
 
+#if GLIB_CHECK_VERSION (2, 14, 0)
+template <typename T, typename ID>
+inline GList *GnomeCmdOwner::HashTable<T,ID>::get_names()
+{
+    return g_hash_table_get_keys (name_table);  //  FIXME:  sort ?
+}
+#endif
 
-inline uid_t OWNER_get_uid_by_name (const gchar *name)
+inline GnomeCmdOwner::GnomeCmdUsers::Entry *GnomeCmdOwner::new_entry(const struct passwd *pw)
 {
-    user_t *user = OWNER_get_user_by_name (name);
+    g_return_val_if_fail (pw!=NULL, NULL);
+
+    GnomeCmdUsers::Entry *entry = users.add(pw->pw_uid, pw->pw_name);
 
-    return user ? user->uid : -1;
+    entry->data.gid = pw->pw_gid;
+    // entry->data.real_name = g_strdup (pw->pw_gecos);     //  not used at the moment
+    // entry->data.zombie = FALSE;
+
+    return entry;
 }
 
+inline GnomeCmdOwner::GnomeCmdGroups::Entry *GnomeCmdOwner::new_entry(const struct group *grp)
+{
+    g_return_val_if_fail (grp!=NULL, NULL);
+
+    GnomeCmdGroups::Entry *entry = groups.add(grp->gr_gid, grp->gr_name);
+
+    // entry->data.zombie = FALSE;
+
+    return entry;
+}
+
+inline GnomeCmdOwner::~GnomeCmdOwner()
+{
+    stop_thread = TRUE;
+    g_thread_join (thread);
+    g_free (buff);
+    g_list_free (group_names);
+}
+
+inline const char *GnomeCmdOwner::get_name_by_uid(uid_t id)
+{
+    GnomeCmdUsers::Entry *entry = users.lookup(id);
+
+    if (entry)
+        return entry->name;
 
-inline gid_t OWNER_get_gid_by_name (const gchar *name)
+    struct passwd pwd, *result=NULL;
+
+    getpwuid_r(id, &pwd, buff, buffsize, &result);
+
+    if (!result)        //  zombie
+    {
+        char s[32];
+
+        snprintf (s, sizeof(s), "%u", id);
+        entry = users.add(id, s);
+        entry->data.zombie = TRUE;
+
+        return entry->name;
+    }
+
+    entry = new_entry(result);
+
+    if (!groups.lookup(entry->data.gid))
+        get_name_by_gid(entry->data.gid);
+
+    return entry->name;
+}
+
+inline const char *GnomeCmdOwner::get_name_by_gid(gid_t id)
 {
-    group_t *group = OWNER_get_group_by_name (name);
+    GnomeCmdGroups::Entry *entry = groups.lookup(id);
 
-    return group ? group->gid : -1;
+    if (entry)
+        return entry->name;
+
+    struct group grp, *result=NULL;
+
+    getgrgid_r(id, &grp, buff, buffsize, &result);
+
+    if (!result)        //  zombie
+    {
+        char s[32];
+
+        snprintf (s, sizeof(s), "%u", id);
+        entry = groups.add(id, s);
+        entry->data.zombie = TRUE;
+
+        return entry->name;
+    }
+
+    entry = new_entry(result);
+
+    return entry->name;
 }
 
+extern GnomeCmdOwner gcmd_owner;
+
 #endif // __OWNER_H__



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]