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