2 Chown-advanced command -- for the Midnight Commander
4 Copyright (C) 1994-2016
5 Free Software Foundation, Inc.
7 This file is part of the Midnight Commander.
9 The Midnight Commander is free software: you can redistribute it
10 and/or modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation, either version 3 of the License,
12 or (at your option) any later version.
14 The Midnight Commander is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 * \brief Source: Contains functions for advanced chowning
33 #include <sys/types.h>
39 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/tty/key.h" /* XCTRL and ALT macros */
44 #include "lib/strutil.h"
45 #include "lib/vfs/vfs.h"
47 #include "lib/widget.h"
50 #include "midnight.h" /* current_panel */
55 /*** global variables ****************************************************************************/
57 /*** file scope macro definitions ****************************************************************/
63 #define BUTTONS_PERM 5
65 #define B_SETALL B_USER
66 #define B_SKIP (B_USER + 1)
67 #define B_OWN (B_USER + 3)
68 #define B_GRP (B_USER + 4)
69 #define B_OTH (B_USER + 5)
70 #define B_OUSER (B_USER + 6)
71 #define B_OGROUP (B_USER + 7)
73 /*** file scope type declarations ****************************************************************/
75 /*** file scope variables ************************************************************************/
77 static WDialog
*ch_dlg
;
86 } chown_advanced_but
[BUTTONS
] =
89 { 0, B_ENTER
, NARROW_BUTTON
, 3, 0, " "},
90 { 0, B_ENTER
, NARROW_BUTTON
, 11, 0, " "},
91 { 0, B_ENTER
, NARROW_BUTTON
, 19, 0, " "},
92 { 0, B_ENTER
, NARROW_BUTTON
, 29, 0, ""},
93 { 0, B_ENTER
, NARROW_BUTTON
, 47, 0, ""},
95 { 0, B_SETALL
, NORMAL_BUTTON
, 0, 0, N_("Set &all")},
96 { 0, B_SKIP
, NORMAL_BUTTON
, 0, 0, N_("S&kip") },
97 { 0, B_ENTER
, DEFPUSH_BUTTON
, 0, 0, N_("&Set") },
98 { 0, B_CANCEL
, NORMAL_BUTTON
, 0, 0, N_("&Cancel") }
102 static WButton
*b_att
[3]; /* permission */
103 static WButton
*b_user
, *b_group
; /* owner */
104 static WLabel
*l_filename
;
105 static WLabel
*l_mode
;
109 static char ch_flags
[11];
110 static const char ch_perm
[] = "rwx";
111 static mode_t ch_cmode
;
112 static struct stat
*sf_stat
;
113 static gboolean need_update
= FALSE
;
114 static gboolean end_chown
= FALSE
;
115 static int current_file
;
116 static gboolean single_set
= FALSE
;
119 /* --------------------------------------------------------------------------------------------- */
120 /*** file scope functions ************************************************************************/
121 /* --------------------------------------------------------------------------------------------- */
124 update_ownership (void)
126 button_set_text (b_user
, get_owner (sf_stat
->st_uid
));
127 button_set_text (b_group
, get_group (sf_stat
->st_gid
));
130 /* --------------------------------------------------------------------------------------------- */
133 inc_flag_pos (int f_pos
)
138 return MSG_NOT_HANDLED
;
141 if ((flag_pos
% 3) == 0 || f_pos
> 2)
142 return MSG_NOT_HANDLED
;
146 /* --------------------------------------------------------------------------------------------- */
149 dec_flag_pos (int f_pos
)
154 return MSG_NOT_HANDLED
;
157 if (((flag_pos
+ 1) % 3) == 0 || f_pos
> 2)
158 return MSG_NOT_HANDLED
;
162 /* --------------------------------------------------------------------------------------------- */
165 set_perm_by_flags (char *s
, int f_p
)
169 for (i
= 0; i
< 3; i
++)
171 if (ch_flags
[f_p
+ i
] == '+')
173 else if (ch_flags
[f_p
+ i
] == '-')
176 s
[i
] = (ch_cmode
& (1 << (8 - f_p
- i
))) ? ch_perm
[i
] : '-';
180 /* --------------------------------------------------------------------------------------------- */
183 update_permissions (void)
185 set_perm_by_flags (b_att
[0]->text
.start
, 0);
186 set_perm_by_flags (b_att
[1]->text
.start
, 3);
187 set_perm_by_flags (b_att
[2]->text
.start
, 6);
190 /* --------------------------------------------------------------------------------------------- */
193 get_perm (char *s
, int base
)
198 m
|= (s
[0] == '-') ? 0 :
199 ((s
[0] == '+') ? (mode_t
) (1 << (base
+ 2)) : (1 << (base
+ 2)) & ch_cmode
);
201 m
|= (s
[1] == '-') ? 0 :
202 ((s
[1] == '+') ? (mode_t
) (1 << (base
+ 1)) : (1 << (base
+ 1)) & ch_cmode
);
204 m
|= (s
[2] == '-') ? 0 : ((s
[2] == '+') ? (mode_t
) (1 << base
) : (1 << base
) & ch_cmode
);
209 /* --------------------------------------------------------------------------------------------- */
216 m
= ch_cmode
^ (ch_cmode
& 0777);
217 m
|= get_perm (ch_flags
, 6);
218 m
|= get_perm (ch_flags
+ 3, 3);
219 m
|= get_perm (ch_flags
+ 6, 0);
224 /* --------------------------------------------------------------------------------------------- */
231 tty_setcolor (COLOR_NORMAL
);
233 for (i
= 0; i
< 3; i
++)
235 widget_move (ch_dlg
, BY
+ 1, 9 + i
);
236 tty_print_char (ch_flags
[i
]);
239 for (i
= 0; i
< 3; i
++)
241 widget_move (ch_dlg
, BY
+ 1, 17 + i
);
242 tty_print_char (ch_flags
[i
+ 3]);
245 for (i
= 0; i
< 3; i
++)
247 widget_move (ch_dlg
, BY
+ 1, 25 + i
);
248 tty_print_char (ch_flags
[i
+ 6]);
251 update_permissions ();
253 for (i
= 0; i
< 15; i
++)
255 widget_move (ch_dlg
, BY
+ 1, 35 + i
);
256 tty_print_char (ch_flags
[9]);
258 for (i
= 0; i
< 15; i
++)
260 widget_move (ch_dlg
, BY
+ 1, 53 + i
);
261 tty_print_char (ch_flags
[10]);
265 /* --------------------------------------------------------------------------------------------- */
268 chown_info_update (void)
270 char buffer
[BUF_SMALL
];
273 g_snprintf (buffer
, sizeof (buffer
), "Permissions (octal): %o", get_mode ());
274 label_set_text (l_mode
, buffer
);
277 update_permissions ();
280 /* --------------------------------------------------------------------------------------------- */
283 update_mode (WDialog
* h
)
286 chown_info_update ();
287 send_message (h
->current
->data
, NULL
, MSG_FOCUS
, 0, NULL
);
290 /* --------------------------------------------------------------------------------------------- */
293 chl_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
303 WDialog
*h
= DIALOG (w
);
313 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
317 /* --------------------------------------------------------------------------------------------- */
320 do_enter_key (WDialog
* h
, int f_pos
)
323 struct passwd
*chl_pass
;
324 struct group
*chl_grp
;
326 gboolean chl_end
, is_owner
;
335 is_owner
= (f_pos
== 3);
336 title
= is_owner
? _("owner") : _("group");
338 lxx
= (COLS
- 74) / 2 + (is_owner
? 35 : 53);
339 lyy
= (LINES
- 13) / 2;
343 dlg_create (TRUE
, lyy
, lxx
, 13, 17, dialog_colors
, chl_callback
, NULL
,
344 "[Advanced Chown]", title
, DLG_COMPACT
);
346 /* get new listboxes */
347 chl_list
= listbox_new (1, 1, 11, 15, FALSE
, NULL
);
348 listbox_add_item (chl_list
, LISTBOX_APPEND_AT_END
, 0, "<Unknown>", NULL
, FALSE
);
351 /* get and put user names in the listbox */
353 while ((chl_pass
= getpwent ()) != NULL
)
354 listbox_add_item (chl_list
, LISTBOX_APPEND_SORTED
, 0, chl_pass
->pw_name
, NULL
,
357 fe
= listbox_search_text (chl_list
, get_owner (sf_stat
->st_uid
));
361 /* get and put group names in the listbox */
363 while ((chl_grp
= getgrent ()) != NULL
)
364 listbox_add_item (chl_list
, LISTBOX_APPEND_SORTED
, 0, chl_grp
->gr_name
, NULL
,
367 fe
= listbox_search_text (chl_list
, get_group (sf_stat
->st_gid
));
370 listbox_select_entry (chl_list
, fe
);
372 b_pos
= chl_list
->pos
;
373 add_widget (chl_dlg
, chl_list
);
375 result
= dlg_run (chl_dlg
);
377 if (result
!= B_CANCEL
)
379 if (b_pos
!= chl_list
->pos
)
384 listbox_get_current (chl_list
, &text
, NULL
);
387 chl_pass
= getpwnam (text
);
388 if (chl_pass
!= NULL
)
391 sf_stat
->st_uid
= chl_pass
->pw_uid
;
396 chl_grp
= getgrnam (text
);
399 sf_stat
->st_gid
= chl_grp
->gr_gid
;
405 ch_flags
[f_pos
+ 6] = '+';
412 if (result
== KEY_LEFT
)
419 else if (result
== KEY_RIGHT
)
423 dlg_one_down (ch_dlg
);
428 /* Here we used to redraw the window */
429 dlg_destroy (chl_dlg
);
434 /* --------------------------------------------------------------------------------------------- */
439 dlg_default_repaint (ch_dlg
);
441 tty_setcolor (COLOR_NORMAL
);
443 widget_move (ch_dlg
, BY
- 1, 8);
444 tty_print_string (_("owner"));
445 widget_move (ch_dlg
, BY
- 1, 16);
446 tty_print_string (_("group"));
447 widget_move (ch_dlg
, BY
- 1, 24);
448 tty_print_string (_("other"));
450 widget_move (ch_dlg
, BY
- 1, 35);
451 tty_print_string (_("owner"));
452 widget_move (ch_dlg
, BY
- 1, 53);
453 tty_print_string (_("group"));
455 widget_move (ch_dlg
, BY
+ 1, 3);
456 tty_print_string (_("Flag"));
461 /* --------------------------------------------------------------------------------------------- */
466 b_att
[0]->hotpos
= -1;
467 b_att
[1]->hotpos
= -1;
468 b_att
[2]->hotpos
= -1;
469 b_att
[f_pos
]->hotpos
= (flag_pos
% 3);
472 /* --------------------------------------------------------------------------------------------- */
475 advanced_chown_callback (Widget
* w
, Widget
* sender
, widget_msg_t msg
, int parm
, void *data
)
477 WDialog
*h
= DIALOG (w
);
482 id
= dlg_get_current_widget_id (h
);
484 for (i
= 0; i
< BUTTONS_PERM
; i
++)
485 if (chown_advanced_but
[i
].id
== id
)
495 chown_info_update ();
506 if ((flag_pos
/ 3) != f_pos
)
507 flag_pos
= f_pos
* 3;
510 else if (f_pos
< BUTTONS_PERM
)
511 flag_pos
= f_pos
+ 6;
519 if (f_pos
< BUTTONS_PERM
)
520 return (dec_flag_pos (f_pos
));
525 if (f_pos
< BUTTONS_PERM
)
526 return (inc_flag_pos (f_pos
));
536 if (f_pos
<= 2 || f_pos
>= BUTTONS_PERM
)
538 do_enter_key (h
, f_pos
);
549 for (i
= 0; i
< 3; i
++)
550 ch_flags
[i
* 3 + parm
- 3] = (x_toggle
& (1 << parm
)) ? '-' : '+';
551 x_toggle
^= (1 << parm
);
553 dlg_broadcast_msg (h
, MSG_DRAW
);
554 send_message (h
->current
->data
, NULL
, MSG_FOCUS
, 0, NULL
);
565 for (i
= 0; i
< 3; i
++)
566 ch_flags
[i
* 3 + parm
] = (x_toggle
& (1 << parm
)) ? '-' : '+';
567 x_toggle
^= (1 << parm
);
569 dlg_broadcast_msg (h
, MSG_DRAW
);
570 send_message (h
->current
->data
, NULL
, MSG_FOCUS
, 0, NULL
);
582 flag_pos
= f_pos
* 3 + i
; /* (strchr(ch_perm,parm)-ch_perm); */
583 if (BUTTON (h
->current
->data
)->text
.start
[(flag_pos
% 3)] == '-')
584 ch_flags
[flag_pos
] = '+';
586 ch_flags
[flag_pos
] = '-';
599 flag_pos
= i
+ f_pos
* 3;
600 ch_flags
[flag_pos
] = '=';
617 ch_flags
[flag_pos
] = parm
;
619 send_message (h
, sender
, MSG_KEY
, KEY_RIGHT
, NULL
);
620 if (flag_pos
> 8 || (flag_pos
% 3) == 0)
628 return MSG_NOT_HANDLED
;
631 return dlg_default_callback (w
, sender
, msg
, parm
, data
);
635 /* --------------------------------------------------------------------------------------------- */
638 init_chown_advanced (void)
645 static gboolean i18n
= FALSE
;
649 for (i
= BUTTONS_PERM
; i
< BUTTONS
; i
++)
652 chown_advanced_but
[i
].text
= _(chown_advanced_but
[i
].text
);
653 #endif /* ENABLE_NLS */
655 chown_advanced_but
[i
].len
= str_term_width1 (chown_advanced_but
[i
].text
) + 3;
656 if (chown_advanced_but
[i
].flags
== DEFPUSH_BUTTON
)
657 chown_advanced_but
[i
].len
+= 2; /* "<>" */
665 sf_stat
= g_new (struct stat
, 1);
667 end_chown
= need_update
= FALSE
;
668 single_set
= (current_panel
->marked
< 2);
669 memset (ch_flags
, '=', 11);
677 dlg_create (TRUE
, 0, 0, dlg_h
, dlg_w
, dialog_colors
, advanced_chown_callback
, NULL
,
678 "[Advanced Chown]", _("Chown advanced command"), DLG_CENTER
);
681 l_filename
= label_new (2, 3, "");
682 add_widget (ch_dlg
, l_filename
);
684 add_widget (ch_dlg
, hline_new (3, -1, -1));
686 #define XTRACT(i,y) y, BX+chown_advanced_but[i].x, \
687 chown_advanced_but[i].ret_cmd, chown_advanced_but[i].flags, \
688 (chown_advanced_but[i].text), NULL
689 b_att
[0] = button_new (XTRACT (0, BY
));
690 chown_advanced_but
[0].id
= add_widget (ch_dlg
, b_att
[0]);
691 b_att
[1] = button_new (XTRACT (1, BY
));
692 chown_advanced_but
[1].id
= add_widget (ch_dlg
, b_att
[1]);
693 b_att
[2] = button_new (XTRACT (2, BY
));
694 chown_advanced_but
[2].id
= add_widget (ch_dlg
, b_att
[2]);
695 b_user
= button_new (XTRACT (3, BY
));
696 chown_advanced_but
[3].id
= add_widget (ch_dlg
, b_user
);
697 b_group
= button_new (XTRACT (4, BY
));
698 chown_advanced_but
[4].id
= add_widget (ch_dlg
, b_group
);
701 l_mode
= label_new (BY
+ 2, 3, "");
702 add_widget (ch_dlg
, l_mode
);
708 add_widget (ch_dlg
, hline_new (y
++, -1, -1));
709 chown_advanced_but
[i
].id
= add_widget (ch_dlg
,
711 WIDGET (ch_dlg
)->cols
/ 2 -
712 chown_advanced_but
[i
].len
,
713 chown_advanced_but
[i
].ret_cmd
,
714 chown_advanced_but
[i
].flags
,
715 chown_advanced_but
[i
].text
, NULL
));
717 chown_advanced_but
[i
].id
= add_widget (ch_dlg
,
718 button_new (y
, WIDGET (ch_dlg
)->cols
/ 2 + 1,
719 chown_advanced_but
[i
].ret_cmd
,
720 chown_advanced_but
[i
].flags
,
721 chown_advanced_but
[i
].text
, NULL
));
725 i
= BUTTONS_PERM
+ 2;
726 add_widget (ch_dlg
, hline_new (y
++, -1, -1));
727 chown_advanced_but
[i
].id
= add_widget (ch_dlg
,
729 WIDGET (ch_dlg
)->cols
/ 2 -
730 chown_advanced_but
[i
].len
,
731 chown_advanced_but
[i
].ret_cmd
,
732 chown_advanced_but
[i
].flags
,
733 chown_advanced_but
[i
].text
, NULL
));
735 chown_advanced_but
[i
].id
= add_widget (ch_dlg
,
736 button_new (y
, WIDGET (ch_dlg
)->cols
/ 2 + 1,
737 chown_advanced_but
[i
].ret_cmd
,
738 chown_advanced_but
[i
].flags
,
739 chown_advanced_but
[i
].text
, NULL
));
741 dlg_select_widget (b_att
[0]);
744 /* --------------------------------------------------------------------------------------------- */
747 chown_advanced_done (void)
751 update_panels (UP_OPTIMIZE
, UP_KEEPSEL
);
755 /* --------------------------------------------------------------------------------------------- */
759 do_chown (uid_t u
, gid_t g
)
761 chown (current_panel
->dir
.list
[current_file
].fname
, u
, g
);
762 file_mark (current_panel
, current_file
, 0);
766 /* --------------------------------------------------------------------------------------------- */
771 while (!current_panel
->dir
.list
[current_file
].f
.marked
)
774 return current_panel
->dir
.list
[current_file
].fname
;
777 /* --------------------------------------------------------------------------------------------- */
780 apply_advanced_chowns (struct stat
*sf
)
784 gid_t a_gid
= sf
->st_gid
;
785 uid_t a_uid
= sf
->st_uid
;
787 lc_fname
= current_panel
->dir
.list
[current_file
].fname
;
788 vpath
= vfs_path_from_str (lc_fname
);
789 need_update
= end_chown
= TRUE
;
790 if (mc_chmod (vpath
, get_mode ()) == -1)
791 message (D_ERROR
, MSG_ERROR
, _("Cannot chmod \"%s\"\n%s"),
792 lc_fname
, unix_error_string (errno
));
793 /* call mc_chown only, if mc_chmod didn't fail */
794 else if (mc_chown (vpath
, (ch_flags
[9] == '+') ? sf
->st_uid
: (uid_t
) (-1),
795 (ch_flags
[10] == '+') ? sf
->st_gid
: (gid_t
) (-1)) == -1)
796 message (D_ERROR
, MSG_ERROR
, _("Cannot chown \"%s\"\n%s"),
797 lc_fname
, unix_error_string (errno
));
798 do_file_mark (current_panel
, current_file
, 0);
799 vfs_path_free (vpath
);
803 lc_fname
= next_file ();
804 vpath
= vfs_path_from_str (lc_fname
);
806 if (mc_stat (vpath
, sf
) != 0)
808 vfs_path_free (vpath
);
812 ch_cmode
= sf
->st_mode
;
814 if (mc_chmod (vpath
, get_mode ()) == -1)
815 message (D_ERROR
, MSG_ERROR
, _("Cannot chmod \"%s\"\n%s"),
816 lc_fname
, unix_error_string (errno
));
817 /* call mc_chown only, if mc_chmod didn't fail */
818 else if (mc_chown (vpath
, (ch_flags
[9] == '+') ? a_uid
: (uid_t
) (-1),
819 (ch_flags
[10] == '+') ? a_gid
: (gid_t
) (-1)) == -1)
820 message (D_ERROR
, MSG_ERROR
, _("Cannot chown \"%s\"\n%s"),
821 lc_fname
, unix_error_string (errno
));
823 do_file_mark (current_panel
, current_file
, 0);
824 vfs_path_free (vpath
);
826 while (current_panel
->marked
!= 0);
829 /* --------------------------------------------------------------------------------------------- */
830 /*** public functions ****************************************************************************/
831 /* --------------------------------------------------------------------------------------------- */
834 chown_advanced_cmd (void)
836 /* Number of files at startup */
839 files_on_begin
= MAX (1, current_panel
->marked
);
842 { /* do while any files remaining */
844 char buffer
[BUF_MEDIUM
];
848 init_chown_advanced ();
850 if (current_panel
->marked
)
851 fname
= next_file (); /* next marked file */
853 fname
= selection (current_panel
)->fname
; /* single file */
854 vpath
= vfs_path_from_str (fname
);
856 if (mc_stat (vpath
, sf_stat
) != 0)
857 { /* get status of file */
858 dlg_destroy (ch_dlg
);
859 vfs_path_free (vpath
);
863 ch_cmode
= sf_stat
->st_mode
;
865 file_idx
= files_on_begin
== 1 ? 1 : (files_on_begin
- current_panel
->marked
+ 1);
866 g_snprintf (buffer
, sizeof (buffer
), "%s (%d/%d)",
867 str_fit_to_term (fname
, WIDGET (ch_dlg
)->cols
- 20, J_LEFT_FIT
),
868 file_idx
, files_on_begin
);
869 label_set_text (l_filename
, buffer
);
873 result
= dlg_run (ch_dlg
);
883 if (mc_chmod (vpath
, get_mode ()) == -1)
884 message (D_ERROR
, MSG_ERROR
, _("Cannot chmod \"%s\"\n%s"),
885 fname
, unix_error_string (errno
));
886 /* call mc_chown only, if mc_chmod didn't fail */
888 (vpath
, (ch_flags
[9] == '+') ? sf_stat
->st_uid
: (uid_t
) (-1),
889 (ch_flags
[10] == '+') ? sf_stat
->st_gid
: (gid_t
) (-1)) == -1)
890 message (D_ERROR
, MSG_ERROR
, _("Cannot chown \"%s\"\n%s"), fname
,
891 unix_error_string (errno
));
895 apply_advanced_chowns (sf_stat
);
903 if (current_panel
->marked
&& result
!= B_CANCEL
)
905 do_file_mark (current_panel
, current_file
, 0);
908 dlg_destroy (ch_dlg
);
909 vfs_path_free (vpath
);
911 while (current_panel
->marked
&& !end_chown
);
913 chown_advanced_done ();
916 /* --------------------------------------------------------------------------------------------- */