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