1 /*
2 ** 1998-06-07 - A command to set the owner and group information on a file
3 ** (or set of files). Might get GUI-ish.
4 ** 1998-06-08 - Fixed the userinfo module, which allowed this one to take another
5 ** step towards completetion; now it preselects the current user/group
6 ** names from the option menus. I still miss some form of higher-level
7 ** control widgetry, though. Later...
8 ** 1998-10-16 - The defaults now work (even if you don't operate the menus).
9 ** 1999-03-06 - Adapted for new selection/generic/dirrow representations.
10 ** 2000-03-23 - Now uses combo boxes rather than menus to display user and group
11 ** lists. Also allows user to type in either number or name of the
12 ** desired user and/or group directly. All in all, a lot smoother.
13 ** 2001-04-24 - Added recursion option.
14 ** 2010-03-02 - Rewritten using GIO.
15 */
16
17 #include "gentoo.h"
18
19 #include <ctype.h>
20 #include <stdlib.h>
21
22 #include "dirpane.h"
23 #include "errors.h"
24 #include "fileutil.h"
25 #include "userinfo.h"
26
27 #include "cmd_generic.h"
28 #include "cmd_chown.h"
29
30 #define CMD_ID "chown"
31
32 /* ----------------------------------------------------------------------------------------- */
33
34 typedef struct {
35 GtkWidget *combo;
36 gint history; /* The weirdly named thing (see gtk_option_menu widget). */
37 } URow;
38
39 typedef struct {
40 GtkWidget *vbox;
41 GtkWidget *label;
42 GtkWidget *rowgrid;
43 URow row[2];
44 guint user, group; /* The currently selected IDs. */
45 gint user_index, group_index; /* Indices to default to. */
46 GtkWidget *recurse;
47 gboolean last_recurse;
48 } ChoInfo;
49
50 /* ----------------------------------------------------------------------------------------- */
51
cho_body(MainInfo * min,DirPane * src,DirRow2 * row,gpointer gen,gpointer user)52 static void cho_body(MainInfo *min, DirPane *src, DirRow2 *row, gpointer gen, gpointer user)
53 {
54 gchar label[2 * MAXNAMLEN + 64];
55 ChoInfo *cho = user;
56
57 g_snprintf(label, sizeof label, _("Set Ownership for '%s':"), dp_row_get_name_display(dp_get_tree_model(src), row));
58 gtk_label_set_text(GTK_LABEL(cho->label), label);
59 gtk_widget_grab_focus(cho->row[0].combo);
60 }
61
62 /* ----------------------------------------------------------------------------------------- */
63
parse_or_lookup(const gchar * str,long lookup (const gchar * name),long * tmp)64 static gboolean parse_or_lookup(const gchar *str, long lookup(const gchar *name), long *tmp)
65 {
66 while(isspace((guchar) *str))
67 str++;
68 if(isdigit((guchar) *str))
69 {
70 gchar *eptr;
71
72 *tmp = strtol(str, &eptr, 10);
73 if(eptr == str)
74 return FALSE;
75 }
76 else
77 *tmp = lookup(str);
78 return TRUE;
79 }
80
get_own(ChoInfo * cho,uid_t * owner,gid_t * group)81 static gboolean get_own(ChoInfo *cho, uid_t *owner, gid_t *group)
82 {
83 const gchar *text;
84 long tmp;
85 gboolean ok = FALSE;
86
87 if((text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(cho->row[0].combo))) == NULL)
88 return FALSE;
89 if(parse_or_lookup(text, usr_lookup_uid, &tmp))
90 {
91 *owner = tmp;
92 if((text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(cho->row[1].combo))) != NULL)
93 {
94 if(parse_or_lookup(text, usr_lookup_gid, &tmp))
95 {
96 *group = tmp;
97 ok = TRUE;
98 }
99 }
100 }
101 return ok;
102 }
103
chown_gfile(MainInfo * min,GFile * file,uid_t owner,gid_t group,gboolean recurse,GError ** err)104 static gboolean chown_gfile(MainInfo *min, GFile *file, uid_t owner, gid_t group, gboolean recurse, GError **err)
105 {
106 gboolean ok = FALSE;
107 GFileInfo *info;
108 GFileType type;
109
110 if(file != NULL && (info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_UNIX_UID "," G_FILE_ATTRIBUTE_UNIX_GID,
111 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, err)) != NULL)
112 {
113 type = g_file_info_get_file_type(info);
114 /* Don't try to change the file's type; now that we've buffered it we can remove it. */
115 g_file_info_remove_attribute(info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
116 g_file_info_set_attribute_uint32(info, G_FILE_ATTRIBUTE_UNIX_UID, owner);
117 g_file_info_set_attribute_uint32(info, G_FILE_ATTRIBUTE_UNIX_GID, group);
118 ok = g_file_set_attributes_from_info(file, info, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, err);
119 g_object_unref(info); /* Drop this early, no point in holding recursively. */
120 if(ok)
121 {
122 if(type == G_FILE_TYPE_DIRECTORY && recurse)
123 {
124 GFileEnumerator *fen;
125
126 ok = FALSE;
127 if((fen = g_file_enumerate_children(file, G_FILE_ATTRIBUTE_STANDARD_NAME, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, err)) != NULL)
128 {
129 GFileInfo *chi;
130
131 ok = TRUE;
132 while(ok && (chi = g_file_enumerator_next_file(fen, NULL, err)) != NULL)
133 {
134 GFile *child = g_file_get_child(file, g_file_info_get_name(chi));
135
136 ok = chown_gfile(min, child, owner, group, recurse, err);
137 g_object_unref(child);
138 }
139 g_object_unref(fen);
140 }
141 }
142 }
143 }
144 return ok;
145 }
146
cho_action(MainInfo * min,DirPane * src,DirPane * dst,DirRow2 * row,GError ** err,gpointer user)147 static gint cho_action(MainInfo *min, DirPane *src, DirPane *dst, DirRow2 *row, GError **err, gpointer user)
148 {
149 ChoInfo *cho = user;
150 uid_t owner = 0;
151 gid_t group = 0;
152 GFile *file;
153 gboolean ok = FALSE;
154
155 if(!get_own(cho, &owner, &group))
156 return FALSE;
157 cho->last_recurse = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(cho->recurse));
158 if((file = dp_get_file_from_row(src, row)) != NULL)
159 {
160 ok = chown_gfile(min, file, owner, group, cho->last_recurse, err);
161 g_object_unref(file);
162 }
163 if(ok)
164 dp_unselect(src, row);
165
166 return ok;
167 }
168
169 /* ----------------------------------------------------------------------------------------- */
170
cmd_chown(MainInfo * min,DirPane * src,DirPane * dst,const CmdArg * ca)171 gint cmd_chown(MainInfo *min, DirPane *src, DirPane *dst, const CmdArg *ca)
172 {
173 UsrCategory cat[] = { UIC_USER, UIC_GROUP };
174 gchar *labtext[] = { N_("User"), N_("Group") };
175 gint i, index;
176 GtkWidget *label;
177 GList *list, *iter;
178 static ChoInfo cho;
179
180 cho.vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
181 cho.label = gtk_label_new("");
182 gtk_box_pack_start(GTK_BOX(cho.vbox), cho.label, FALSE, FALSE, 0);
183 cho.rowgrid = gtk_grid_new();
184 for(i = 0; i < 2; i++)
185 {
186 label = gtk_label_new(_(labtext[i]));
187 gtk_grid_attach(GTK_GRID(cho.rowgrid), label, 0, i, 1, 1);
188 cho.row[i].combo = gtk_combo_box_text_new_with_entry();
189 list = usr_string_list_create(cat[i], cat[i] == UIC_USER ? geteuid() : getgid(), &index);
190 for(iter = list; iter != NULL; iter = g_list_next(iter))
191 gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(cho.row[i].combo), iter->data);
192 gtk_combo_box_set_active(GTK_COMBO_BOX(cho.row[i].combo), index);
193 usr_string_list_destroy(list);
194 gtk_widget_set_hexpand(cho.row[i].combo, TRUE);
195 gtk_widget_set_halign(cho.row[i].combo, GTK_ALIGN_FILL);
196 gtk_grid_attach(GTK_GRID(cho.rowgrid), cho.row[i].combo, 1, i, 1, 1);
197 }
198 gtk_box_pack_start(GTK_BOX(cho.vbox), cho.rowgrid, FALSE, FALSE, 5);
199 cho.recurse = gtk_check_button_new_with_label(_("Recurse Directories?"));
200 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cho.recurse), cho.last_recurse);
201 gtk_box_pack_start(GTK_BOX(cho.vbox), cho.recurse, FALSE, FALSE, 0);
202 gtk_widget_show_all(cho.vbox);
203
204 return cmd_generic(min, _("Change Ownership"), CGF_SRC | CGF_NODST, cho_body, cho_action, NULL, &cho);
205 }
206