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