This source file includes following definitions.
- chmod_init
- chmod_draw_select
- chmod_toggle_select
- chmod_refresh
- chmod_bg_callback
- chmod_callback
- chmod_dlg_create
- chmod_done
- try_chmod
- do_chmod
- apply_mask
- chmod_cmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 #include <config.h>
28
29 #include <errno.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33
34 #include "lib/global.h"
35
36 #include "lib/tty/tty.h"
37 #include "lib/skin.h"
38 #include "lib/vfs/vfs.h"
39 #include "lib/strutil.h"
40 #include "lib/util.h"
41 #include "lib/widget.h"
42
43 #include "src/util.h"
44
45 #include "cmd.h"
46
47
48
49
50
51 #define PX 3
52 #define PY 2
53
54 #define B_MARKED B_USER
55 #define B_SETALL (B_USER + 1)
56 #define B_SETMRK (B_USER + 2)
57 #define B_CLRMRK (B_USER + 3)
58
59 #define BUTTONS 6
60 #define BUTTONS_PERM 12
61 #define LABELS 4
62
63
64
65
66
67
68
69 static struct
70 {
71 mode_t mode;
72 const char *text;
73 gboolean selected;
74 WCheck *check;
75 } check_perm[BUTTONS_PERM] = {
76 { S_ISUID, N_ ("set &user ID on execution"), FALSE, NULL },
77 { S_ISGID, N_ ("set &group ID on execution"), FALSE, NULL },
78 { S_ISVTX, N_ ("stick&y bit"), FALSE, NULL },
79 { S_IRUSR, N_ ("&read by owner"), FALSE, NULL },
80 { S_IWUSR, N_ ("&write by owner"), FALSE, NULL },
81 { S_IXUSR, N_ ("e&xecute/search by owner"), FALSE, NULL },
82 { S_IRGRP, N_ ("rea&d by group"), FALSE, NULL },
83 { S_IWGRP, N_ ("write by grou&p"), FALSE, NULL },
84 { S_IXGRP, N_ ("execu&te/search by group"), FALSE, NULL },
85 { S_IROTH, N_ ("read &by others"), FALSE, NULL },
86 { S_IWOTH, N_ ("wr&ite by others"), FALSE, NULL },
87 { S_IXOTH, N_ ("execute/searc&h by others"), FALSE, NULL },
88 };
89
90 static int check_perm_len = 0;
91
92 static const char *file_info_labels[LABELS] = {
93 N_ ("Name:"),
94 N_ ("Permissions (octal):"),
95 N_ ("Owner name:"),
96 N_ ("Group name:"),
97 };
98
99 static int file_info_labels_len = 0;
100
101 static struct
102 {
103 int ret_cmd;
104 button_flags_t flags;
105 int y;
106 const char *text;
107 } chmod_but[BUTTONS] = {
108 { B_SETALL, NORMAL_BUTTON, 6, N_ ("Set &all") },
109 { B_MARKED, NORMAL_BUTTON, 6, N_ ("&Marked all") },
110 { B_SETMRK, NORMAL_BUTTON, 5, N_ ("S&et marked") },
111 { B_CLRMRK, NORMAL_BUTTON, 5, N_ ("C&lear marked") },
112 { B_ENTER, DEFPUSH_BUTTON, 3, N_ ("&Set") },
113 { B_CANCEL, NORMAL_BUTTON, 3, N_ ("&Cancel") },
114 };
115
116 static gboolean mode_change;
117 static int current_file;
118 static gboolean ignore_all;
119
120 static mode_t and_mask, or_mask, ch_mode;
121
122 static WLabel *statl;
123 static WGroupbox *file_gb;
124
125
126
127
128
129 static void
130 chmod_init (void)
131 {
132 static gboolean i18n = FALSE;
133 int i, len;
134
135 for (i = 0; i < BUTTONS_PERM; i++)
136 check_perm[i].selected = FALSE;
137
138 if (i18n)
139 return;
140
141 i18n = TRUE;
142
143 #ifdef ENABLE_NLS
144 for (i = 0; i < BUTTONS_PERM; i++)
145 check_perm[i].text = _ (check_perm[i].text);
146
147 for (i = 0; i < LABELS; i++)
148 file_info_labels[i] = _ (file_info_labels[i]);
149
150 for (i = 0; i < BUTTONS; i++)
151 chmod_but[i].text = _ (chmod_but[i].text);
152 #endif
153
154 for (i = 0; i < BUTTONS_PERM; i++)
155 {
156 len = str_term_width1 (check_perm[i].text);
157 check_perm_len = MAX (check_perm_len, len);
158 }
159
160 check_perm_len += 1 + 3 + 1;
161
162 for (i = 0; i < LABELS; i++)
163 {
164 len = str_term_width1 (file_info_labels[i]) + 2;
165 file_info_labels_len = MAX (file_info_labels_len, len);
166 }
167 }
168
169
170
171 static void
172 chmod_draw_select (const WDialog *h, int Id)
173 {
174 widget_gotoyx (h, PY + Id + 1, PX + 1);
175 tty_print_char (check_perm[Id].selected ? '*' : ' ');
176 widget_gotoyx (h, PY + Id + 1, PX + 3);
177 }
178
179
180
181 static void
182 chmod_toggle_select (const WDialog *h, int Id)
183 {
184 check_perm[Id].selected = !check_perm[Id].selected;
185 tty_setcolor (COLOR_NORMAL);
186 chmod_draw_select (h, Id);
187 }
188
189
190
191 static void
192 chmod_refresh (const WDialog *h)
193 {
194 int i;
195 int y, x;
196
197 tty_setcolor (COLOR_NORMAL);
198
199 for (i = 0; i < BUTTONS_PERM; i++)
200 chmod_draw_select (h, i);
201
202 y = WIDGET (file_gb)->rect.y + 1;
203 x = WIDGET (file_gb)->rect.x + 2;
204
205 tty_gotoyx (y, x);
206 tty_print_string (file_info_labels[0]);
207 tty_gotoyx (y + 2, x);
208 tty_print_string (file_info_labels[1]);
209 tty_gotoyx (y + 4, x);
210 tty_print_string (file_info_labels[2]);
211 tty_gotoyx (y + 6, x);
212 tty_print_string (file_info_labels[3]);
213 }
214
215
216
217 static cb_ret_t
218 chmod_bg_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
219 {
220 switch (msg)
221 {
222 case MSG_DRAW:
223 frame_callback (w, NULL, MSG_DRAW, 0, NULL);
224 chmod_refresh (CONST_DIALOG (w->owner));
225 return MSG_HANDLED;
226
227 default:
228 return frame_callback (w, sender, msg, parm, data);
229 }
230 }
231
232
233
234 static cb_ret_t
235 chmod_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
236 {
237 WGroup *g = GROUP (w);
238 WDialog *h = DIALOG (w);
239
240 switch (msg)
241 {
242 case MSG_NOTIFY:
243 {
244
245 int i;
246
247
248 for (i = 0; i < BUTTONS_PERM; i++)
249 if (sender == WIDGET (check_perm[i].check))
250 break;
251
252 if (i < BUTTONS_PERM)
253 {
254 ch_mode ^= check_perm[i].mode;
255 label_set_textv (statl, "%o", (unsigned int) ch_mode);
256 chmod_toggle_select (h, i);
257 mode_change = TRUE;
258 return MSG_HANDLED;
259 }
260 }
261
262 return MSG_NOT_HANDLED;
263
264 case MSG_KEY:
265 if (parm == 'T' || parm == 't' || parm == KEY_IC)
266 {
267 int i;
268 unsigned long id;
269
270 id = group_get_current_widget_id (g);
271 for (i = 0; i < BUTTONS_PERM; i++)
272 if (id == WIDGET (check_perm[i].check)->id)
273 break;
274
275 if (i < BUTTONS_PERM)
276 {
277 chmod_toggle_select (h, i);
278 if (parm == KEY_IC)
279 group_select_next_widget (g);
280 return MSG_HANDLED;
281 }
282 }
283 return MSG_NOT_HANDLED;
284
285 default:
286 return dlg_default_callback (w, sender, msg, parm, data);
287 }
288 }
289
290
291
292 static WDialog *
293 chmod_dlg_create (WPanel *panel, const char *fname, const struct stat *sf_stat)
294 {
295 gboolean single_set;
296 WDialog *ch_dlg;
297 WGroup *g;
298 int lines, cols;
299 int i, y;
300 int perm_gb_len;
301 int file_gb_len;
302 const char *c_fname, *c_fown, *c_fgrp;
303 char buffer[BUF_TINY];
304
305 mode_change = FALSE;
306
307 single_set = (panel->marked < 2);
308 perm_gb_len = check_perm_len + 2;
309 file_gb_len = file_info_labels_len + 2;
310 cols = str_term_width1 (fname) + 2 + 1;
311 file_gb_len = MAX (file_gb_len, cols);
312
313 lines = single_set ? 20 : 23;
314 cols = perm_gb_len + file_gb_len + 1 + 6;
315
316 if (cols > COLS)
317 {
318
319 cols = COLS;
320 file_gb_len = cols - (perm_gb_len + 1 + 6);
321 }
322
323 ch_dlg = dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors, chmod_callback,
324 NULL, "[Chmod]", _ ("Chmod command"));
325 g = GROUP (ch_dlg);
326
327
328 ch_dlg->bg->callback = chmod_bg_callback;
329
330 group_add_widget (g, groupbox_new (PY, PX, BUTTONS_PERM + 2, perm_gb_len, _ ("Permission")));
331
332 for (i = 0; i < BUTTONS_PERM; i++)
333 {
334 check_perm[i].check =
335 check_new (PY + i + 1, PX + 2, (ch_mode & check_perm[i].mode) != 0, check_perm[i].text);
336 group_add_widget (g, check_perm[i].check);
337 }
338
339 file_gb = groupbox_new (PY, PX + perm_gb_len + 1, BUTTONS_PERM + 2, file_gb_len, _ ("File"));
340 group_add_widget (g, file_gb);
341
342
343 y = PY + 2;
344 cols = PX + perm_gb_len + 3;
345 c_fname = str_trunc (fname, file_gb_len - 3);
346 group_add_widget (g, label_new (y, cols, c_fname));
347 g_snprintf (buffer, sizeof (buffer), "%o", (unsigned int) ch_mode);
348 statl = label_new (y + 2, cols, buffer);
349 group_add_widget (g, statl);
350 c_fown = str_trunc (get_owner (sf_stat->st_uid), file_gb_len - 3);
351 group_add_widget (g, label_new (y + 4, cols, c_fown));
352 c_fgrp = str_trunc (get_group (sf_stat->st_gid), file_gb_len - 3);
353 group_add_widget (g, label_new (y + 6, cols, c_fgrp));
354
355 for (i = single_set ? BUTTONS - 2 : 0; i < BUTTONS; i++)
356 {
357 WButton *b;
358
359 y = lines - chmod_but[i].y;
360
361 if (i == 0 || i == BUTTONS - 2)
362 group_add_widget (g, hline_new (y - 1, -1, -1));
363
364 b = button_new (y, 1, chmod_but[i].ret_cmd, chmod_but[i].flags, chmod_but[i].text, NULL);
365 WIDGET (b)->rect.x = WIDGET (ch_dlg)->rect.cols / 2 - button_get_width (b);
366 group_add_widget (g, b);
367 i++;
368 b = button_new (y, 1, chmod_but[i].ret_cmd, chmod_but[i].flags, chmod_but[i].text, NULL);
369 WIDGET (b)->rect.x = WIDGET (ch_dlg)->rect.cols / 2 + 1;
370 group_add_widget (g, b);
371 }
372
373
374 widget_select (WIDGET (check_perm[0].check));
375
376 return ch_dlg;
377 }
378
379
380
381 static void
382 chmod_done (gboolean need_update)
383 {
384 if (need_update)
385 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
386 repaint_screen ();
387 }
388
389
390
391 static gboolean
392 try_chmod (const vfs_path_t *p, mode_t m)
393 {
394 const char *fname = NULL;
395
396 while (mc_chmod (p, m) == -1 && !ignore_all)
397 {
398 int my_errno = errno;
399
400 if (fname == NULL)
401 fname = x_basename (vfs_path_as_str (p));
402
403 errno = my_errno;
404
405 switch (file_error (NULL, TRUE, _ ("Cannot chmod\n%sn%s"), fname))
406 {
407 case FILE_IGNORE:
408
409 return TRUE;
410
411 case FILE_IGNORE_ALL:
412 ignore_all = TRUE;
413
414 return TRUE;
415
416 case FILE_RETRY:
417
418 break;
419
420 case FILE_ABORT:
421 default:
422
423 return FALSE;
424 }
425 }
426
427 return TRUE;
428 }
429
430
431
432 static gboolean
433 do_chmod (WPanel *panel, const vfs_path_t *p, struct stat *sf)
434 {
435 gboolean ret;
436
437 sf->st_mode &= and_mask;
438 sf->st_mode |= or_mask;
439
440 ret = try_chmod (p, sf->st_mode);
441
442 do_file_mark (panel, current_file, 0);
443
444 return ret;
445 }
446
447
448
449 static void
450 apply_mask (WPanel *panel, vfs_path_t *vpath, struct stat *sf)
451 {
452 gboolean ok;
453
454 if (!do_chmod (panel, vpath, sf))
455 return;
456
457 do
458 {
459 const GString *fname;
460
461 fname = panel_find_marked_file (panel, ¤t_file);
462 vpath = vfs_path_from_str (fname->str);
463 ok = (mc_stat (vpath, sf) == 0);
464
465 if (!ok)
466 {
467
468
469 do_file_mark (panel, current_file, 0);
470
471
472 ok = TRUE;
473 }
474 else
475 {
476 ch_mode = sf->st_mode;
477
478 ok = do_chmod (panel, vpath, sf);
479 }
480
481 vfs_path_free (vpath, TRUE);
482 }
483 while (ok && panel->marked != 0);
484 }
485
486
487
488
489
490 void
491 chmod_cmd (WPanel *panel)
492 {
493 gboolean need_update;
494 gboolean end_chmod;
495
496 chmod_init ();
497
498 current_file = 0;
499 ignore_all = FALSE;
500
501 do
502 {
503 vfs_path_t *vpath;
504 WDialog *ch_dlg;
505 struct stat sf_stat;
506 const GString *fname;
507 int i, result;
508
509 do_refresh ();
510
511 need_update = FALSE;
512 end_chmod = FALSE;
513
514 fname = panel_get_marked_file (panel, ¤t_file);
515 if (fname == NULL)
516 break;
517
518 vpath = vfs_path_from_str (fname->str);
519
520 if (mc_stat (vpath, &sf_stat) != 0)
521 {
522 vfs_path_free (vpath, TRUE);
523 break;
524 }
525
526 ch_mode = sf_stat.st_mode;
527
528 ch_dlg = chmod_dlg_create (panel, fname->str, &sf_stat);
529 result = dlg_run (ch_dlg);
530
531 switch (result)
532 {
533 case B_CANCEL:
534 end_chmod = TRUE;
535 break;
536
537 case B_ENTER:
538 if (mode_change)
539 {
540 if (panel->marked <= 1)
541 {
542
543 if (mc_chmod (vpath, ch_mode) == -1 && !ignore_all)
544 file_error_message (_ ("Cannot chmod\n%s"), fname->str);
545 end_chmod = TRUE;
546 }
547 else if (!try_chmod (vpath, ch_mode))
548 {
549
550 result = B_CANCEL;
551 end_chmod = TRUE;
552 }
553 }
554
555 need_update = TRUE;
556 break;
557
558 case B_SETALL:
559 case B_MARKED:
560 and_mask = or_mask = 0;
561 and_mask = ~and_mask;
562
563 for (i = 0; i < BUTTONS_PERM; i++)
564 if (check_perm[i].selected || result == B_SETALL)
565 {
566 if (check_perm[i].check->state)
567 or_mask |= check_perm[i].mode;
568 else
569 and_mask &= ~check_perm[i].mode;
570 }
571
572 apply_mask (panel, vpath, &sf_stat);
573 need_update = TRUE;
574 end_chmod = TRUE;
575 break;
576
577 case B_SETMRK:
578 and_mask = or_mask = 0;
579 and_mask = ~and_mask;
580
581 for (i = 0; i < BUTTONS_PERM; i++)
582 if (check_perm[i].selected)
583 or_mask |= check_perm[i].mode;
584
585 apply_mask (panel, vpath, &sf_stat);
586 need_update = TRUE;
587 end_chmod = TRUE;
588 break;
589
590 case B_CLRMRK:
591 and_mask = or_mask = 0;
592 and_mask = ~and_mask;
593
594 for (i = 0; i < BUTTONS_PERM; i++)
595 if (check_perm[i].selected)
596 and_mask &= ~check_perm[i].mode;
597
598 apply_mask (panel, vpath, &sf_stat);
599 need_update = TRUE;
600 end_chmod = TRUE;
601 break;
602
603 default:
604 break;
605 }
606
607 if (panel->marked != 0 && result != B_CANCEL)
608 {
609 do_file_mark (panel, current_file, 0);
610 need_update = TRUE;
611 }
612
613 vfs_path_free (vpath, TRUE);
614
615 widget_destroy (WIDGET (ch_dlg));
616 }
617 while (panel->marked != 0 && !end_chmod);
618
619 chmod_done (need_update);
620 }
621
622