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