This source file includes following definitions.
- advanced_chown_init
- inc_flag_pos
- dec_flag_pos
- set_perm_by_flags
- get_perm
- get_mode
- update_permissions
- update_ownership
- print_flags
- advanced_chown_refresh
- advanced_chown_info_update
- update_mode
- perm_button_callback
- perm_button_mouse_callback
- perm_button_new
- chl_callback
- user_group_button_cb
- advanced_chown_bg_callback
- advanced_chown_callback
- advanced_chown_dlg_create
- advanced_chown_done
- next_file
- try_advanced_chown
- do_advanced_chown
- apply_advanced_chowns
- advanced_chown_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 <stdio.h>
31 #include <string.h>
32 #include <pwd.h>
33 #include <grp.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <unistd.h>
37
38 #include "lib/global.h"
39
40 #include "lib/tty/tty.h"
41 #include "lib/tty/key.h"
42 #include "lib/skin.h"
43 #include "lib/vfs/vfs.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h"
46 #include "lib/widget.h"
47
48 #include "cmd.h"
49
50
51
52
53
54 #define BX 5
55 #define BY 5
56
57 #define BUTTONS 9
58 #define BUTTONS_PERM 5
59
60 #define B_SETALL B_USER
61 #define B_SKIP (B_USER + 1)
62
63
64
65
66
67 static struct
68 {
69 unsigned long id;
70 int ret_cmd;
71 button_flags_t flags;
72 int x;
73 int len;
74 const char *text;
75 } advanced_chown_but[BUTTONS] =
76 {
77
78 { 0, B_ENTER, NARROW_BUTTON, 3, 0, " " },
79 { 0, B_ENTER, NARROW_BUTTON, 11, 0, " " },
80 { 0, B_ENTER, NARROW_BUTTON, 19, 0, " " },
81 { 0, B_ENTER, NARROW_BUTTON, 29, 0, "" },
82 { 0, B_ENTER, NARROW_BUTTON, 47, 0, "" },
83
84 { 0, B_SETALL, NORMAL_BUTTON, 0, 0, N_("Set &all") },
85 { 0, B_SKIP, NORMAL_BUTTON, 0, 0, N_("S&kip") },
86 { 0, B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("&Set") },
87 { 0, B_CANCEL, NORMAL_BUTTON, 0, 0, N_("&Cancel") }
88
89 };
90
91 static int current_file;
92 static gboolean ignore_all;
93
94 static WButton *b_att[3];
95 static WButton *b_user, *b_group;
96 static WLabel *l_filename;
97 static WLabel *l_mode;
98
99 static int flag_pos;
100 static int x_toggle;
101 static char ch_flags[11];
102 static const char ch_perm[] = "rwx";
103 static mode_t ch_cmode;
104 static struct stat sf_stat;
105
106
107
108
109
110 static void
111 advanced_chown_init (void)
112 {
113 static gboolean i18n = FALSE;
114 int i;
115
116 if (i18n)
117 return;
118
119 i18n = TRUE;
120
121 for (i = BUTTONS_PERM; i < BUTTONS; i++)
122 {
123 #ifdef ENABLE_NLS
124 advanced_chown_but[i].text = _(advanced_chown_but[i].text);
125 #endif
126
127 advanced_chown_but[i].len = str_term_width1 (advanced_chown_but[i].text) + 3;
128 if (advanced_chown_but[i].flags == DEFPUSH_BUTTON)
129 advanced_chown_but[i].len += 2;
130 }
131
132 }
133
134
135
136 static cb_ret_t
137 inc_flag_pos (void)
138 {
139 if (flag_pos == 10)
140 {
141 flag_pos = 0;
142 return MSG_NOT_HANDLED;
143 }
144
145 flag_pos++;
146
147 return flag_pos % 3 == 0 ? MSG_NOT_HANDLED : MSG_HANDLED;
148 }
149
150
151
152 static cb_ret_t
153 dec_flag_pos (void)
154 {
155 if (flag_pos == 0)
156 {
157 flag_pos = 10;
158 return MSG_NOT_HANDLED;
159 }
160
161 flag_pos--;
162
163 return (flag_pos + 1) % 3 == 0 ? MSG_NOT_HANDLED : MSG_HANDLED;
164 }
165
166
167
168 static void
169 set_perm_by_flags (char *s, int f_p)
170 {
171 int i;
172
173 for (i = 0; i < 3; i++)
174 {
175 if (ch_flags[f_p + i] == '+')
176 s[i] = ch_perm[i];
177 else if (ch_flags[f_p + i] == '-')
178 s[i] = '-';
179 else
180 s[i] = (ch_cmode & (1 << (8 - f_p - i))) != 0 ? ch_perm[i] : '-';
181 }
182 }
183
184
185
186 static mode_t
187 get_perm (char *s, int base)
188 {
189 mode_t m = 0;
190
191 m |= (s[0] == '-') ? 0 :
192 ((s[0] == '+') ? (mode_t) (1 << (base + 2)) : (1 << (base + 2)) & ch_cmode);
193
194 m |= (s[1] == '-') ? 0 :
195 ((s[1] == '+') ? (mode_t) (1 << (base + 1)) : (1 << (base + 1)) & ch_cmode);
196
197 m |= (s[2] == '-') ? 0 : ((s[2] == '+') ? (mode_t) (1 << base) : (1 << base) & ch_cmode);
198
199 return m;
200 }
201
202
203
204 static mode_t
205 get_mode (void)
206 {
207 mode_t m;
208
209 m = ch_cmode ^ (ch_cmode & 0777);
210 m |= get_perm (ch_flags, 6);
211 m |= get_perm (ch_flags + 3, 3);
212 m |= get_perm (ch_flags + 6, 0);
213
214 return m;
215 }
216
217
218
219 static void
220 update_permissions (void)
221 {
222 set_perm_by_flags (b_att[0]->text.start, 0);
223 set_perm_by_flags (b_att[1]->text.start, 3);
224 set_perm_by_flags (b_att[2]->text.start, 6);
225 }
226
227
228
229 static void
230 update_ownership (void)
231 {
232 button_set_text (b_user, get_owner (sf_stat.st_uid));
233 button_set_text (b_group, get_group (sf_stat.st_gid));
234 }
235
236
237
238 static void
239 print_flags (const WDialog * h)
240 {
241 int i;
242
243 tty_setcolor (COLOR_NORMAL);
244
245 for (i = 0; i < 3; i++)
246 {
247 widget_gotoyx (h, BY + 1, advanced_chown_but[0].x + 6 + i);
248 tty_print_char (ch_flags[i]);
249 }
250
251 for (i = 0; i < 3; i++)
252 {
253 widget_gotoyx (h, BY + 1, advanced_chown_but[1].x + 6 + i);
254 tty_print_char (ch_flags[i + 3]);
255 }
256
257 for (i = 0; i < 3; i++)
258 {
259 widget_gotoyx (h, BY + 1, advanced_chown_but[2].x + 6 + i);
260 tty_print_char (ch_flags[i + 6]);
261 }
262
263 update_permissions ();
264
265 for (i = 0; i < 15; i++)
266 {
267 widget_gotoyx (h, BY + 1, advanced_chown_but[3].x + 6 + i);
268 tty_print_char (ch_flags[9]);
269 }
270 for (i = 0; i < 15; i++)
271 {
272 widget_gotoyx (h, BY + 1, advanced_chown_but[4].x + 6 + i);
273 tty_print_char (ch_flags[10]);
274 }
275 }
276
277
278
279 static void
280 advanced_chown_refresh (const WDialog * h)
281 {
282 tty_setcolor (COLOR_NORMAL);
283
284 widget_gotoyx (h, BY - 1, advanced_chown_but[0].x + 5);
285 tty_print_string (_("owner"));
286 widget_gotoyx (h, BY - 1, advanced_chown_but[1].x + 5);
287 tty_print_string (_("group"));
288 widget_gotoyx (h, BY - 1, advanced_chown_but[2].x + 5);
289 tty_print_string (_("other"));
290
291 widget_gotoyx (h, BY - 1, advanced_chown_but[3].x + 5);
292 tty_print_string (_("owner"));
293 widget_gotoyx (h, BY - 1, advanced_chown_but[4].x + 5);
294 tty_print_string (_("group"));
295
296 widget_gotoyx (h, BY + 1, 3);
297 tty_print_string (_("Flag"));
298 print_flags (h);
299 }
300
301
302
303 static void
304 advanced_chown_info_update (void)
305 {
306
307 label_set_textv (l_mode, _("Permissions (octal): %o"), get_mode ());
308
309
310 update_permissions ();
311 }
312
313
314
315 static void
316 update_mode (WGroup * g)
317 {
318 print_flags (DIALOG (g));
319 advanced_chown_info_update ();
320 widget_set_state (WIDGET (g->current->data), WST_FOCUSED, TRUE);
321 }
322
323
324
325 static cb_ret_t
326 perm_button_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
327 {
328 WButton *b = BUTTON (w);
329 WGroup *g = w->owner;
330 int i = 0;
331 int f_pos;
332
333
334 if (b == b_att[0])
335 f_pos = 0;
336 else if (b == b_att[1])
337 f_pos = 1;
338 else
339 f_pos = 2;
340
341 switch (msg)
342 {
343 case MSG_FOCUS:
344 if (b->hotpos == -1)
345 b->hotpos = 0;
346
347 flag_pos = f_pos * 3 + b->hotpos;
348 return MSG_HANDLED;
349
350 case MSG_KEY:
351 switch (parm)
352 {
353 case '*':
354 parm = '=';
355 MC_FALLTHROUGH;
356
357 case '-':
358 case '=':
359 case '+':
360 flag_pos = f_pos * 3 + b->hotpos;
361 ch_flags[flag_pos] = parm;
362 update_mode (g);
363 send_message (w, NULL, MSG_KEY, KEY_RIGHT, NULL);
364 if (b->hotpos == 2)
365 group_select_next_widget (g);
366 break;
367
368 case XCTRL ('f'):
369 case KEY_RIGHT:
370 {
371 cb_ret_t ret;
372
373 ret = inc_flag_pos ();
374 b->hotpos = flag_pos % 3;
375 return ret;
376 }
377
378 case XCTRL ('b'):
379 case KEY_LEFT:
380 {
381 cb_ret_t ret;
382
383 ret = dec_flag_pos ();
384 b->hotpos = flag_pos % 3;
385 return ret;
386 }
387
388 case 'x':
389 i++;
390 MC_FALLTHROUGH;
391
392 case 'w':
393 i++;
394 MC_FALLTHROUGH;
395
396 case 'r':
397 b->hotpos = i;
398 MC_FALLTHROUGH;
399
400 case ' ':
401 i = b->hotpos;
402
403 flag_pos = f_pos * 3 + i;
404 if (b->text.start[flag_pos % 3] == '-')
405 ch_flags[flag_pos] = '+';
406 else
407 ch_flags[flag_pos] = '-';
408 update_mode (w->owner);
409 break;
410
411 case '4':
412 i++;
413 MC_FALLTHROUGH;
414
415 case '2':
416 i++;
417 MC_FALLTHROUGH;
418
419 case '1':
420 b->hotpos = i;
421 flag_pos = f_pos * 3 + i;
422 ch_flags[flag_pos] = '=';
423 update_mode (g);
424 break;
425
426 default:
427 break;
428 }
429
430 return MSG_NOT_HANDLED;
431
432 default:
433 return button_default_callback (w, sender, msg, parm, data);
434 }
435 }
436
437
438
439 static void
440 perm_button_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
441 {
442 switch (msg)
443 {
444 case MSG_MOUSE_DOWN:
445
446 BUTTON (w)->hotpos = CLAMP (event->x - 1, 0, 2);
447 MC_FALLTHROUGH;
448
449 default:
450 button_mouse_default_callback (w, msg, event);
451 break;
452 }
453 }
454
455
456
457 static WButton *
458 perm_button_new (int y, int x, int action, button_flags_t flags, const char *text,
459 bcback_fn callback)
460 {
461 WButton *b;
462 Widget *w;
463
464
465 b = button_new (y, x, action, flags, text, callback);
466 w = WIDGET (b);
467
468
469 widget_want_hotkey (w, FALSE);
470
471 w->callback = perm_button_callback;
472 w->mouse_callback = perm_button_mouse_callback;
473
474 return b;
475 }
476
477
478
479 static cb_ret_t
480 chl_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
481 {
482 switch (msg)
483 {
484 case MSG_KEY:
485 switch (parm)
486 {
487 case KEY_LEFT:
488 case KEY_RIGHT:
489 {
490 WDialog *h = DIALOG (w);
491
492 h->ret_value = parm;
493 dlg_stop (h);
494 }
495 break;
496 default:
497 break;
498 }
499 MC_FALLTHROUGH;
500
501 default:
502 return dlg_default_callback (w, sender, msg, parm, data);
503 }
504 }
505
506
507
508 static int
509 user_group_button_cb (WButton * button, int action)
510 {
511 Widget *w = WIDGET (button);
512 int f_pos;
513 gboolean chl_end;
514
515 (void) action;
516
517 if (button == b_user)
518 f_pos = BUTTONS_PERM - 2;
519 else if (button == b_group)
520 f_pos = BUTTONS_PERM - 1;
521 else
522 return 0;
523
524 do
525 {
526 WGroup *g = w->owner;
527 WDialog *h = DIALOG (g);
528 Widget *wh = WIDGET (h);
529
530 gboolean is_owner = (f_pos == BUTTONS_PERM - 2);
531 const char *title;
532 int lxx, b_pos;
533 WDialog *chl_dlg;
534 WListbox *chl_list;
535 int result;
536 int fe;
537 struct passwd *chl_pass;
538 struct group *chl_grp;
539
540 chl_end = FALSE;
541
542 if (is_owner)
543 {
544 title = _("owner");
545 lxx = WIDGET (b_user)->rect.x + 1;
546 }
547 else
548 {
549 title = _("group");
550 lxx = WIDGET (b_group)->rect.x + 1;
551 }
552
553 chl_dlg =
554 dlg_create (TRUE, wh->rect.y - 1, lxx, wh->rect.lines + 2, 17, WPOS_KEEP_DEFAULT, TRUE,
555 dialog_colors, chl_callback, NULL, "[Advanced Chown]", title);
556
557
558 chl_list =
559 listbox_new (1, 1, WIDGET (chl_dlg)->rect.lines - 2, WIDGET (chl_dlg)->rect.cols - 2,
560 FALSE, NULL);
561 listbox_add_item (chl_list, LISTBOX_APPEND_AT_END, 0, "<Unknown>", NULL, FALSE);
562 if (is_owner)
563 {
564
565 setpwent ();
566 while ((chl_pass = getpwent ()) != NULL)
567 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_pass->pw_name, NULL,
568 FALSE);
569 endpwent ();
570 fe = listbox_search_text (chl_list, get_owner (sf_stat.st_uid));
571 }
572 else
573 {
574
575 setgrent ();
576 while ((chl_grp = getgrent ()) != NULL)
577 listbox_add_item (chl_list, LISTBOX_APPEND_SORTED, 0, chl_grp->gr_name, NULL,
578 FALSE);
579 endgrent ();
580 fe = listbox_search_text (chl_list, get_group (sf_stat.st_gid));
581 }
582
583 listbox_select_entry (chl_list, fe);
584
585 b_pos = chl_list->pos;
586 group_add_widget (GROUP (chl_dlg), chl_list);
587
588 result = dlg_run (chl_dlg);
589
590 if (result != B_CANCEL)
591 {
592 if (b_pos != chl_list->pos)
593 {
594 gboolean ok = FALSE;
595 char *text;
596
597 listbox_get_current (chl_list, &text, NULL);
598 if (is_owner)
599 {
600 chl_pass = getpwnam (text);
601 if (chl_pass != NULL)
602 {
603 sf_stat.st_uid = chl_pass->pw_uid;
604 ok = TRUE;
605 }
606 }
607 else
608 {
609 chl_grp = getgrnam (text);
610 if (chl_grp != NULL)
611 {
612 sf_stat.st_gid = chl_grp->gr_gid;
613 ok = TRUE;
614 }
615 }
616
617 if (!ok)
618 group_select_current_widget (g);
619 else
620 {
621 ch_flags[f_pos + 6] = '+';
622 update_ownership ();
623 group_select_current_widget (g);
624 print_flags (h);
625 }
626 }
627
628 if (result == KEY_LEFT)
629 {
630 if (!is_owner)
631 chl_end = TRUE;
632 group_select_prev_widget (g);
633 f_pos--;
634 }
635 else if (result == KEY_RIGHT)
636 {
637 if (is_owner)
638 chl_end = TRUE;
639 group_select_next_widget (g);
640 f_pos++;
641 }
642 }
643
644
645 widget_destroy (WIDGET (chl_dlg));
646 }
647 while (chl_end);
648
649 return 0;
650 }
651
652
653
654 static cb_ret_t
655 advanced_chown_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
656 {
657 switch (msg)
658 {
659 case MSG_DRAW:
660 frame_callback (w, NULL, MSG_DRAW, 0, NULL);
661 advanced_chown_refresh (DIALOG (w->owner));
662 advanced_chown_info_update ();
663 return MSG_HANDLED;
664
665 default:
666 return frame_callback (w, sender, msg, parm, data);
667 }
668 }
669
670
671
672 static cb_ret_t
673 advanced_chown_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
674 {
675 WGroup *g = GROUP (w);
676 int i = 0;
677
678 switch (msg)
679 {
680 case MSG_KEY:
681 switch (parm)
682 {
683 case ALT ('x'):
684 i++;
685 MC_FALLTHROUGH;
686
687 case ALT ('w'):
688 i++;
689 MC_FALLTHROUGH;
690
691 case ALT ('r'):
692 parm = i + 3;
693 for (i = 0; i < 3; i++)
694 ch_flags[i * 3 + parm - 3] = (x_toggle & (1 << parm)) ? '-' : '+';
695 x_toggle ^= (1 << parm);
696 update_mode (g);
697 widget_draw (w);
698 break;
699
700 case XCTRL ('x'):
701 i++;
702 MC_FALLTHROUGH;
703
704 case XCTRL ('w'):
705 i++;
706 MC_FALLTHROUGH;
707
708 case XCTRL ('r'):
709 parm = i;
710 for (i = 0; i < 3; i++)
711 ch_flags[i * 3 + parm] = (x_toggle & (1 << parm)) ? '-' : '+';
712 x_toggle ^= (1 << parm);
713 update_mode (g);
714 widget_draw (w);
715 break;
716
717 default:
718 break;
719 }
720 return MSG_NOT_HANDLED;
721
722 default:
723 return dlg_default_callback (w, sender, msg, parm, data);
724 }
725 }
726
727
728
729 static WDialog *
730 advanced_chown_dlg_create (WPanel * panel)
731 {
732 gboolean single_set;
733 WDialog *ch_dlg;
734 WGroup *ch_grp;
735 int lines = 12;
736 int cols = 74;
737 int i;
738 int y;
739
740 memset (ch_flags, '=', 11);
741 flag_pos = 0;
742 x_toggle = 070;
743
744 single_set = (panel->marked < 2);
745 if (!single_set)
746 lines += 2;
747
748 ch_dlg =
749 dlg_create (TRUE, 0, 0, lines, cols, WPOS_CENTER, FALSE, dialog_colors,
750 advanced_chown_callback, NULL, "[Advanced Chown]", _("Chown advanced command"));
751 ch_grp = GROUP (ch_dlg);
752
753
754 ch_dlg->bg->callback = advanced_chown_bg_callback;
755
756 l_filename = label_new (2, 3, "");
757 group_add_widget (ch_grp, l_filename);
758
759 group_add_widget (ch_grp, hline_new (3, -1, -1));
760
761 #define XTRACT(i,y,cb) y, BX+advanced_chown_but[i].x, \
762 advanced_chown_but[i].ret_cmd, advanced_chown_but[i].flags, \
763 (advanced_chown_but[i].text), cb
764 b_att[0] = perm_button_new (XTRACT (0, BY, NULL));
765 advanced_chown_but[0].id = group_add_widget (ch_grp, b_att[0]);
766 b_att[1] = perm_button_new (XTRACT (1, BY, NULL));
767 advanced_chown_but[1].id = group_add_widget (ch_grp, b_att[1]);
768 b_att[2] = perm_button_new (XTRACT (2, BY, NULL));
769 advanced_chown_but[2].id = group_add_widget (ch_grp, b_att[2]);
770 b_user = button_new (XTRACT (3, BY, user_group_button_cb));
771 advanced_chown_but[3].id = group_add_widget (ch_grp, b_user);
772 b_group = button_new (XTRACT (4, BY, user_group_button_cb));
773 advanced_chown_but[4].id = group_add_widget (ch_grp, b_group);
774
775 l_mode = label_new (BY + 2, 3, "");
776 group_add_widget (ch_grp, l_mode);
777
778 y = BY + 3;
779 if (!single_set)
780 {
781 i = BUTTONS_PERM;
782 group_add_widget (ch_grp, hline_new (y++, -1, -1));
783 advanced_chown_but[i].id = group_add_widget (ch_grp,
784 button_new (y,
785 WIDGET (ch_dlg)->rect.cols / 2 -
786 advanced_chown_but[i].len,
787 advanced_chown_but[i].ret_cmd,
788 advanced_chown_but[i].flags,
789 advanced_chown_but[i].text, NULL));
790 i++;
791 advanced_chown_but[i].id = group_add_widget (ch_grp,
792 button_new (y,
793 WIDGET (ch_dlg)->rect.cols / 2 + 1,
794 advanced_chown_but[i].ret_cmd,
795 advanced_chown_but[i].flags,
796 advanced_chown_but[i].text, NULL));
797 y++;
798 }
799
800 i = BUTTONS_PERM + 2;
801 group_add_widget (ch_grp, hline_new (y++, -1, -1));
802 advanced_chown_but[i].id = group_add_widget (ch_grp,
803 button_new (y,
804 WIDGET (ch_dlg)->rect.cols / 2 -
805 advanced_chown_but[i].len,
806 advanced_chown_but[i].ret_cmd,
807 advanced_chown_but[i].flags,
808 advanced_chown_but[i].text, NULL));
809 i++;
810 advanced_chown_but[i].id = group_add_widget (ch_grp,
811 button_new (y, WIDGET (ch_dlg)->rect.cols / 2 + 1,
812 advanced_chown_but[i].ret_cmd,
813 advanced_chown_but[i].flags,
814 advanced_chown_but[i].text, NULL));
815
816 widget_select (WIDGET (b_att[0]));
817
818 return ch_dlg;
819 }
820
821
822
823 static void
824 advanced_chown_done (gboolean need_update)
825 {
826 if (need_update)
827 update_panels (UP_OPTIMIZE, UP_KEEPSEL);
828 repaint_screen ();
829 }
830
831
832
833 static const GString *
834 next_file (const WPanel * panel)
835 {
836 while (!panel->dir.list[current_file].f.marked)
837 current_file++;
838
839 return panel->dir.list[current_file].fname;
840 }
841
842
843
844 static gboolean
845 try_advanced_chown (const vfs_path_t * p, mode_t m, uid_t u, gid_t g)
846 {
847 int chmod_result;
848 const char *fname;
849
850 fname = x_basename (vfs_path_as_str (p));
851
852 while ((chmod_result = mc_chmod (p, m)) == -1 && !ignore_all)
853 {
854 int my_errno = errno;
855 int result;
856 char *msg;
857
858 msg = g_strdup_printf (_("Cannot chmod \"%s\"\n%s"), fname, unix_error_string (my_errno));
859 result =
860 query_dialog (MSG_ERROR, msg, D_ERROR, 4, _("&Ignore"), _("Ignore &all"), _("&Retry"),
861 _("&Cancel"));
862 g_free (msg);
863
864 switch (result)
865 {
866 case 0:
867
868 return TRUE;
869
870 case 1:
871 ignore_all = TRUE;
872
873 return TRUE;
874
875 case 2:
876
877 break;
878
879 case 3:
880 default:
881
882 return FALSE;
883 }
884 }
885
886
887 while (chmod_result != -1 && mc_chown (p, u, g) == -1 && !ignore_all)
888 {
889 int my_errno = errno;
890 int result;
891 char *msg;
892
893 msg = g_strdup_printf (_("Cannot chown \"%s\"\n%s"), fname, unix_error_string (my_errno));
894 result =
895 query_dialog (MSG_ERROR, msg, D_ERROR, 4, _("&Ignore"), _("Ignore &all"), _("&Retry"),
896 _("&Cancel"));
897 g_free (msg);
898
899 switch (result)
900 {
901 case 0:
902
903 return TRUE;
904
905 case 1:
906 ignore_all = TRUE;
907
908 return TRUE;
909
910 case 2:
911
912 break;
913
914 case 3:
915 default:
916
917 return FALSE;
918 }
919 }
920
921 return TRUE;
922
923 }
924
925
926
927 static gboolean
928 do_advanced_chown (WPanel * panel, const vfs_path_t * p, mode_t m, uid_t u, gid_t g)
929 {
930 gboolean ret;
931
932 ret = try_advanced_chown (p, m, u, g);
933
934 do_file_mark (panel, current_file, 0);
935
936 return ret;
937 }
938
939
940
941 static void
942 apply_advanced_chowns (WPanel * panel, vfs_path_t * vpath, struct stat *sf)
943 {
944 gid_t a_gid = sf->st_gid;
945 uid_t a_uid = sf->st_uid;
946 gboolean ok;
947
948 if (!do_advanced_chown (panel, vpath, get_mode (),
949 (ch_flags[9] == '+') ? a_uid : (uid_t) (-1),
950 (ch_flags[10] == '+') ? a_gid : (gid_t) (-1)))
951 return;
952
953 do
954 {
955 const GString *fname;
956
957 fname = next_file (panel);
958 vpath = vfs_path_from_str (fname->str);
959 ok = (mc_stat (vpath, sf) == 0);
960
961 if (!ok)
962 {
963
964
965 do_file_mark (panel, current_file, 0);
966
967
968 ok = TRUE;
969 }
970 else
971 {
972 ch_cmode = sf->st_mode;
973
974 ok = do_advanced_chown (panel, vpath, get_mode (),
975 (ch_flags[9] == '+') ? a_uid : (uid_t) (-1),
976 (ch_flags[10] == '+') ? a_gid : (gid_t) (-1));
977 }
978
979 vfs_path_free (vpath, TRUE);
980 }
981 while (ok && panel->marked != 0);
982 }
983
984
985
986
987
988 void
989 advanced_chown_cmd (WPanel * panel)
990 {
991 gboolean need_update;
992 gboolean end_chown;
993
994
995 int files_on_begin;
996
997 files_on_begin = MAX (1, panel->marked);
998
999 advanced_chown_init ();
1000
1001 current_file = 0;
1002 ignore_all = FALSE;
1003
1004 do
1005 {
1006 vfs_path_t *vpath;
1007 WDialog *ch_dlg;
1008 const GString *fname;
1009 int result;
1010 int file_idx;
1011
1012 do_refresh ();
1013
1014 need_update = FALSE;
1015 end_chown = FALSE;
1016
1017 if (panel->marked != 0)
1018 fname = next_file (panel);
1019 else
1020 fname = selection (panel)->fname;
1021
1022 vpath = vfs_path_from_str (fname->str);
1023
1024 if (mc_stat (vpath, &sf_stat) != 0)
1025 {
1026 vfs_path_free (vpath, TRUE);
1027 break;
1028 }
1029
1030 ch_cmode = sf_stat.st_mode;
1031
1032 ch_dlg = advanced_chown_dlg_create (panel);
1033
1034 file_idx = files_on_begin == 1 ? 1 : (files_on_begin - panel->marked + 1);
1035 label_set_textv (l_filename, "%s (%d/%d)",
1036 str_fit_to_term (fname->str, WIDGET (ch_dlg)->rect.cols - 20, J_LEFT_FIT),
1037 file_idx, files_on_begin);
1038 update_ownership ();
1039
1040 result = dlg_run (ch_dlg);
1041
1042 switch (result)
1043 {
1044 case B_CANCEL:
1045 end_chown = TRUE;
1046 break;
1047
1048 case B_ENTER:
1049 if (panel->marked <= 1)
1050 {
1051
1052 if (mc_chmod (vpath, get_mode ()) == -1)
1053 message (D_ERROR, MSG_ERROR, _("Cannot chmod \"%s\"\n%s"),
1054 fname->str, unix_error_string (errno));
1055
1056 else if (mc_chown
1057 (vpath, (ch_flags[9] == '+') ? sf_stat.st_uid : (uid_t) (-1),
1058 (ch_flags[10] == '+') ? sf_stat.st_gid : (gid_t) (-1)) == -1)
1059 message (D_ERROR, MSG_ERROR, _("Cannot chown \"%s\"\n%s"), fname->str,
1060 unix_error_string (errno));
1061
1062 end_chown = TRUE;
1063 }
1064 else if (!try_advanced_chown
1065 (vpath, get_mode (), (ch_flags[9] == '+') ? sf_stat.st_uid : (uid_t) (-1),
1066 (ch_flags[10] == '+') ? sf_stat.st_gid : (gid_t) (-1)))
1067 {
1068
1069 result = B_CANCEL;
1070 end_chown = TRUE;
1071 }
1072
1073 need_update = TRUE;
1074 break;
1075
1076 case B_SETALL:
1077 apply_advanced_chowns (panel, vpath, &sf_stat);
1078 need_update = TRUE;
1079 end_chown = TRUE;
1080 break;
1081
1082 case B_SKIP:
1083 default:
1084 break;
1085 }
1086
1087 if (panel->marked != 0 && result != B_CANCEL)
1088 {
1089 do_file_mark (panel, current_file, 0);
1090 need_update = TRUE;
1091 }
1092
1093 vfs_path_free (vpath, TRUE);
1094
1095 widget_destroy (WIDGET (ch_dlg));
1096 }
1097 while (panel->marked != 0 && !end_chown);
1098
1099 advanced_chown_done (need_update);
1100 }
1101
1102