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