This source file includes following definitions.
- i_cache_match
- i_cache_add
- my_fork
- my_system__save_sigaction_handlers
- my_system__restore_sigaction_handlers
- my_system_make_arg_array
- mc_pread_stream
- get_owner
- get_group
- save_stop_handler
- my_exit
- my_system
- my_systeml
- my_systemv
- my_systemv_flags
- mc_popen
- mc_pread
- mc_pstream_get_string
- mc_pclose
- tilde_expand
- custom_canonicalize_pathname
- canonicalize_pathname
- mc_realpath
- get_user_permissions
- mc_build_filenamev
- mc_build_filename
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
28
29
30
31
32
33
34
35
36
37 #include <config.h>
38
39 #include <ctype.h>
40 #include <errno.h>
41 #include <limits.h>
42 #include <signal.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #ifdef HAVE_SYS_PARAM_H
48 #include <sys/param.h>
49 #endif
50 #include <sys/types.h>
51 #include <sys/stat.h>
52 #ifdef HAVE_SYS_SELECT_H
53 #include <sys/select.h>
54 #endif
55 #include <sys/wait.h>
56 #include <pwd.h>
57 #include <grp.h>
58
59 #include "lib/global.h"
60
61 #include "lib/unixcompat.h"
62 #include "lib/vfs/vfs.h"
63 #include "lib/strutil.h"
64 #include "lib/util.h"
65 #include "lib/widget.h"
66 #include "lib/vfs/xdirentry.h"
67
68 #ifdef HAVE_CHARSET
69 #include "lib/charsets.h"
70 #endif
71
72 #include "utilunix.h"
73
74
75
76 struct sigaction startup_handler;
77
78
79
80 #define UID_CACHE_SIZE 200
81 #define GID_CACHE_SIZE 30
82
83
84
85 typedef struct
86 {
87 int index;
88 char *string;
89 } int_cache;
90
91 typedef enum
92 {
93 FORK_ERROR = -1,
94 FORK_CHILD,
95 FORK_PARENT,
96 } my_fork_state_t;
97
98 typedef struct
99 {
100 struct sigaction intr;
101 struct sigaction quit;
102 struct sigaction stop;
103 } my_system_sigactions_t;
104
105
106
107 static int_cache uid_cache[UID_CACHE_SIZE];
108 static int_cache gid_cache[GID_CACHE_SIZE];
109
110
111
112
113
114 static char *
115 i_cache_match (int id, int_cache * cache, int size)
116 {
117 int i;
118
119 for (i = 0; i < size; i++)
120 if (cache[i].index == id)
121 return cache[i].string;
122 return 0;
123 }
124
125
126
127 static void
128 i_cache_add (int id, int_cache * cache, int size, char *text, int *last)
129 {
130 g_free (cache[*last].string);
131 cache[*last].string = g_strdup (text);
132 cache[*last].index = id;
133 *last = ((*last) + 1) % size;
134 }
135
136
137
138 static my_fork_state_t
139 my_fork (void)
140 {
141 pid_t pid;
142
143 pid = fork ();
144
145 if (pid < 0)
146 {
147 fprintf (stderr, "\n\nfork () = -1\n");
148 return FORK_ERROR;
149 }
150
151 if (pid == 0)
152 return FORK_CHILD;
153
154 while (TRUE)
155 {
156 int status = 0;
157
158 if (waitpid (pid, &status, 0) > 0)
159 return WEXITSTATUS (status) == 0 ? FORK_PARENT : FORK_ERROR;
160
161 if (errno != EINTR)
162 return FORK_ERROR;
163 }
164 }
165
166
167
168 static void
169 my_system__save_sigaction_handlers (my_system_sigactions_t * sigactions)
170 {
171 struct sigaction ignore;
172
173 memset (&ignore, 0, sizeof (ignore));
174 ignore.sa_handler = SIG_IGN;
175 sigemptyset (&ignore.sa_mask);
176
177 sigaction (SIGINT, &ignore, &sigactions->intr);
178 sigaction (SIGQUIT, &ignore, &sigactions->quit);
179
180
181
182 sigaction (SIGTSTP, &startup_handler, &sigactions->stop);
183 }
184
185
186
187 static void
188 my_system__restore_sigaction_handlers (my_system_sigactions_t * sigactions)
189 {
190 sigaction (SIGINT, &sigactions->intr, NULL);
191 sigaction (SIGQUIT, &sigactions->quit, NULL);
192 sigaction (SIGTSTP, &sigactions->stop, NULL);
193 }
194
195
196
197 static GPtrArray *
198 my_system_make_arg_array (int flags, const char *shell, char **execute_name)
199 {
200 GPtrArray *args_array;
201
202 args_array = g_ptr_array_new ();
203
204 if ((flags & EXECUTE_AS_SHELL) != 0)
205 {
206 g_ptr_array_add (args_array, (gpointer) shell);
207 g_ptr_array_add (args_array, (gpointer) "-c");
208 *execute_name = g_strdup (shell);
209 }
210 else
211 {
212 char *shell_token;
213
214 shell_token = shell != NULL ? strchr (shell, ' ') : NULL;
215 if (shell_token == NULL)
216 *execute_name = g_strdup (shell);
217 else
218 *execute_name = g_strndup (shell, (gsize) (shell_token - shell));
219
220 g_ptr_array_add (args_array, (gpointer) shell);
221 }
222 return args_array;
223 }
224
225
226
227 static void
228 mc_pread_stream (mc_pipe_stream_t * ps, const fd_set * fds)
229 {
230 size_t buf_len;
231 ssize_t read_len;
232
233 if (!FD_ISSET (ps->fd, fds))
234 {
235 ps->len = MC_PIPE_STREAM_UNREAD;
236 return;
237 }
238
239 buf_len = (size_t) ps->len;
240
241 if (buf_len >= MC_PIPE_BUFSIZE)
242 buf_len = ps->null_term ? MC_PIPE_BUFSIZE - 1 : MC_PIPE_BUFSIZE;
243
244 do
245 {
246 read_len = read (ps->fd, ps->buf, buf_len);
247 }
248 while (read_len < 0 && errno == EINTR);
249
250 if (read_len < 0)
251 {
252
253 ps->len = MC_PIPE_ERROR_READ;
254 ps->error = errno;
255 }
256 else if (read_len == 0)
257
258 ps->len = MC_PIPE_STREAM_EOF;
259 else
260 {
261
262 ps->len = read_len;
263
264 if (ps->null_term)
265 ps->buf[(size_t) ps->len] = '\0';
266 }
267
268 ps->pos = 0;
269 }
270
271
272
273
274
275 const char *
276 get_owner (uid_t uid)
277 {
278 struct passwd *pwd;
279 char *name;
280 static uid_t uid_last;
281
282 name = i_cache_match ((int) uid, uid_cache, UID_CACHE_SIZE);
283 if (name != NULL)
284 return name;
285
286 pwd = getpwuid (uid);
287 if (pwd != NULL)
288 {
289 i_cache_add ((int) uid, uid_cache, UID_CACHE_SIZE, pwd->pw_name, (int *) &uid_last);
290 return pwd->pw_name;
291 }
292 else
293 {
294 static char ibuf[10];
295
296 g_snprintf (ibuf, sizeof (ibuf), "%d", (int) uid);
297 return ibuf;
298 }
299 }
300
301
302
303 const char *
304 get_group (gid_t gid)
305 {
306 struct group *grp;
307 char *name;
308 static gid_t gid_last;
309
310 name = i_cache_match ((int) gid, gid_cache, GID_CACHE_SIZE);
311 if (name != NULL)
312 return name;
313
314 grp = getgrgid (gid);
315 if (grp != NULL)
316 {
317 i_cache_add ((int) gid, gid_cache, GID_CACHE_SIZE, grp->gr_name, (int *) &gid_last);
318 return grp->gr_name;
319 }
320 else
321 {
322 static char gbuf[10];
323
324 g_snprintf (gbuf, sizeof (gbuf), "%d", (int) gid);
325 return gbuf;
326 }
327 }
328
329
330
331
332
333
334 void
335 save_stop_handler (void)
336 {
337 sigaction (SIGTSTP, NULL, &startup_handler);
338 }
339
340
341
342
343
344
345
346
347
348
349 void
350
351 my_exit (int status)
352 {
353 _exit (status);
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368 int
369 my_system (int flags, const char *shell, const char *command)
370 {
371 return my_systeml (flags, shell, command, NULL);
372 }
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388 int
389 my_systeml (int flags, const char *shell, ...)
390 {
391 GPtrArray *args_array;
392 int status = 0;
393 va_list vargs;
394 char *one_arg;
395
396 args_array = g_ptr_array_new ();
397
398 va_start (vargs, shell);
399 while ((one_arg = va_arg (vargs, char *)) != NULL)
400 g_ptr_array_add (args_array, one_arg);
401 va_end (vargs);
402
403 g_ptr_array_add (args_array, NULL);
404 status = my_systemv_flags (flags, shell, (char *const *) args_array->pdata);
405
406 g_ptr_array_free (args_array, TRUE);
407
408 return status;
409 }
410
411
412
413
414
415
416
417
418
419
420
421 int
422 my_systemv (const char *command, char *const argv[])
423 {
424 my_fork_state_t fork_state;
425 int status = 0;
426 my_system_sigactions_t sigactions;
427
428 my_system__save_sigaction_handlers (&sigactions);
429
430 fork_state = my_fork ();
431 switch (fork_state)
432 {
433 case FORK_ERROR:
434 status = -1;
435 break;
436 case FORK_CHILD:
437 {
438 signal (SIGINT, SIG_DFL);
439 signal (SIGQUIT, SIG_DFL);
440 signal (SIGTSTP, SIG_DFL);
441 signal (SIGCHLD, SIG_DFL);
442
443 execvp (command, argv);
444 my_exit (127);
445 }
446 MC_FALLTHROUGH;
447
448 default:
449 status = 0;
450 break;
451 }
452 my_system__restore_sigaction_handlers (&sigactions);
453
454 return status;
455 }
456
457
458
459
460
461
462
463
464
465
466
467
468
469 int
470 my_systemv_flags (int flags, const char *command, char *const argv[])
471 {
472 char *execute_name = NULL;
473 GPtrArray *args_array;
474 int status = 0;
475
476 args_array = my_system_make_arg_array (flags, command, &execute_name);
477
478 for (; argv != NULL && *argv != NULL; argv++)
479 g_ptr_array_add (args_array, *argv);
480
481 g_ptr_array_add (args_array, NULL);
482 status = my_systemv (execute_name, (char *const *) args_array->pdata);
483
484 g_free (execute_name);
485 g_ptr_array_free (args_array, TRUE);
486
487 return status;
488 }
489
490
491
492
493
494
495
496
497
498
499
500
501
502 mc_pipe_t *
503 mc_popen (const char *command, gboolean read_out, gboolean read_err, GError ** error)
504 {
505 mc_pipe_t *p;
506 const char *const argv[] = { "/bin/sh", "sh", "-c", command, NULL };
507
508 p = g_try_new (mc_pipe_t, 1);
509 if (p == NULL)
510 {
511 mc_replace_error (error, MC_PIPE_ERROR_CREATE_PIPE, "%s",
512 _("Cannot create pipe descriptor"));
513 goto ret_err;
514 }
515
516 p->out.fd = -1;
517 p->err.fd = -1;
518
519 if (!g_spawn_async_with_pipes
520 (NULL, (gchar **) argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_FILE_AND_ARGV_ZERO, NULL,
521 NULL, &p->child_pid, NULL, read_out ? &p->out.fd : NULL, read_err ? &p->err.fd : NULL,
522 error))
523 {
524 mc_replace_error (error, MC_PIPE_ERROR_CREATE_PIPE_STREAM, "%s",
525 _("Cannot create pipe streams"));
526 goto ret_err;
527 }
528
529 p->out.buf[0] = '\0';
530 p->out.len = MC_PIPE_BUFSIZE;
531 p->out.null_term = FALSE;
532
533 p->err.buf[0] = '\0';
534 p->err.len = MC_PIPE_BUFSIZE;
535 p->err.null_term = FALSE;
536
537 return p;
538
539 ret_err:
540 g_free (p);
541 return NULL;
542 }
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564 void
565 mc_pread (mc_pipe_t * p, GError ** error)
566 {
567 gboolean read_out, read_err;
568 fd_set fds;
569 int maxfd = 0;
570 int res;
571
572 if (error != NULL)
573 *error = NULL;
574
575 read_out = p->out.fd >= 0;
576 read_err = p->err.fd >= 0;
577
578 if (!read_out && !read_err)
579 {
580 p->out.len = MC_PIPE_STREAM_UNREAD;
581 p->err.len = MC_PIPE_STREAM_UNREAD;
582 return;
583 }
584
585 FD_ZERO (&fds);
586 if (read_out)
587 {
588 FD_SET (p->out.fd, &fds);
589 maxfd = p->out.fd;
590 }
591
592 if (read_err)
593 {
594 FD_SET (p->err.fd, &fds);
595 maxfd = MAX (maxfd, p->err.fd);
596 }
597
598
599 res = select (maxfd + 1, &fds, NULL, NULL, NULL);
600 if (res < 0 && errno != EINTR)
601 {
602 mc_propagate_error (error, MC_PIPE_ERROR_READ,
603 _
604 ("Unexpected error in select() reading data from a child process:\n%s"),
605 unix_error_string (errno));
606 return;
607 }
608
609 if (read_out)
610 mc_pread_stream (&p->out, &fds);
611 else
612 p->out.len = MC_PIPE_STREAM_UNREAD;
613
614 if (read_err)
615 mc_pread_stream (&p->err, &fds);
616 else
617 p->err.len = MC_PIPE_STREAM_UNREAD;
618 }
619
620
621
622
623
624
625
626
627
628
629
630 GString *
631 mc_pstream_get_string (mc_pipe_stream_t * ps)
632 {
633 char *s;
634 size_t size, i;
635 gboolean escape = FALSE;
636
637 g_return_val_if_fail (ps != NULL, NULL);
638
639 if (ps->len < 0)
640 return NULL;
641
642 size = ps->len - ps->pos;
643
644 if (size == 0)
645 return NULL;
646
647 s = ps->buf + ps->pos;
648
649 if (s[0] == '\0')
650 return NULL;
651
652
653 for (i = 0; i < size && !(s[i] == '\0' || (s[i] == '\n' && !escape)); i++)
654 escape = s[i] == '\\' ? !escape : FALSE;
655
656 if (i != size && s[i] == '\n')
657 i++;
658
659 ps->pos += i;
660
661 return g_string_new_len (s, i);
662 }
663
664
665
666
667
668
669
670
671
672 void
673 mc_pclose (mc_pipe_t * p, GError ** error)
674 {
675 int res;
676
677 if (p->out.fd >= 0)
678 res = close (p->out.fd);
679 if (p->err.fd >= 0)
680 res = close (p->err.fd);
681
682 do
683 {
684 int status;
685
686 res = waitpid (p->child_pid, &status, 0);
687 }
688 while (res < 0 && errno == EINTR);
689
690 if (res < 0)
691 mc_replace_error (error, MC_PIPE_ERROR_READ, _("Unexpected error in waitpid():\n%s"),
692 unix_error_string (errno));
693
694 g_free (p);
695 }
696
697
698
699
700
701
702
703
704
705
706
707 char *
708 tilde_expand (const char *directory)
709 {
710 struct passwd *passwd;
711 const char *p, *q;
712
713 if (*directory != '~')
714 return g_strdup (directory);
715
716 p = directory + 1;
717
718
719 if (*p == '\0' || IS_PATH_SEP (*p))
720 {
721 passwd = getpwuid (geteuid ());
722 q = IS_PATH_SEP (*p) ? p + 1 : "";
723 }
724 else
725 {
726 q = strchr (p, PATH_SEP);
727 if (q == NULL)
728 passwd = getpwnam (p);
729 else
730 {
731 char *name;
732
733 name = g_strndup (p, q - p);
734 passwd = getpwnam (name);
735 q++;
736 g_free (name);
737 }
738 }
739
740
741 if (passwd == NULL)
742 return g_strdup (directory);
743
744 return g_strconcat (passwd->pw_dir, PATH_SEP_STR, q, (char *) NULL);
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758
759 void
760 custom_canonicalize_pathname (char *path, CANON_PATH_FLAGS flags)
761 {
762 char *p, *s;
763 char *lpath = path;
764 const size_t url_delim_len = strlen (VFS_PATH_URL_DELIMITER);
765
766
767 if ((flags & CANON_PATH_GUARDUNC) != 0 && IS_PATH_SEP (path[0]) && IS_PATH_SEP (path[1]))
768 {
769 for (p = path + 2; p[0] != '\0' && !IS_PATH_SEP (p[0]); p++)
770 ;
771 if (IS_PATH_SEP (p[0]) && p > path + 2)
772 lpath = p;
773 }
774
775 if (lpath[0] == '\0' || lpath[1] == '\0')
776 return;
777
778 if ((flags & CANON_PATH_JOINSLASHES) != 0)
779 {
780
781 for (p = lpath; *p != '\0'; p++)
782 if (IS_PATH_SEP (p[0]) && IS_PATH_SEP (p[1]) && (p == lpath || *(p - 1) != ':'))
783 {
784 s = p + 1;
785 while (IS_PATH_SEP (*(++s)))
786 ;
787 str_move (p + 1, s);
788 }
789
790
791 for (p = lpath; *p != '\0';)
792 if (IS_PATH_SEP (p[0]) && p[1] == '.' && IS_PATH_SEP (p[2]))
793 str_move (p, p + 2);
794 else
795 p++;
796 }
797
798 if ((flags & CANON_PATH_REMSLASHDOTS) != 0)
799 {
800 size_t len;
801
802
803 for (p = lpath + strlen (lpath) - 1; p > lpath && IS_PATH_SEP (*p); p--)
804 {
805 if (p >= lpath + url_delim_len - 1
806 && strncmp (p - url_delim_len + 1, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
807 break;
808 *p = '\0';
809 }
810
811
812 if (lpath[0] == '.' && IS_PATH_SEP (lpath[1]))
813 {
814 if (lpath[2] == '\0')
815 {
816 lpath[1] = '\0';
817 return;
818 }
819
820 str_move (lpath, lpath + 2);
821 }
822
823
824 len = strlen (lpath);
825 if (len < 2)
826 return;
827
828 if (IS_PATH_SEP (lpath[len - 1])
829 && (len < url_delim_len
830 || strncmp (lpath + len - url_delim_len, VFS_PATH_URL_DELIMITER,
831 url_delim_len) != 0))
832 lpath[len - 1] = '\0';
833 else if (lpath[len - 1] == '.' && IS_PATH_SEP (lpath[len - 2]))
834 {
835 if (len == 2)
836 {
837 lpath[1] = '\0';
838 return;
839 }
840
841 lpath[len - 2] = '\0';
842 }
843 }
844
845
846 if ((flags & CANON_PATH_REMDOUBLEDOTS) != 0)
847 {
848 #ifdef HAVE_CHARSET
849 const size_t enc_prefix_len = strlen (VFS_ENCODING_PREFIX);
850 #endif
851
852 for (p = lpath; p[0] != '\0' && p[1] != '\0' && p[2] != '\0';)
853 {
854 if (!IS_PATH_SEP (p[0]) || p[1] != '.' || p[2] != '.'
855 || (!IS_PATH_SEP (p[3]) && p[3] != '\0'))
856 {
857 p++;
858 continue;
859 }
860
861
862 s = p - 1;
863 if (s >= lpath + url_delim_len - 2
864 && strncmp (s - url_delim_len + 2, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
865 {
866 s -= (url_delim_len - 2);
867 while (s >= lpath && !IS_PATH_SEP (*s--))
868 ;
869 }
870
871 while (s >= lpath)
872 {
873 if (s - url_delim_len > lpath
874 && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
875 {
876 char *vfs_prefix = s - url_delim_len;
877 vfs_class *vclass;
878
879 while (vfs_prefix > lpath && !IS_PATH_SEP (*--vfs_prefix))
880 ;
881 if (IS_PATH_SEP (*vfs_prefix))
882 vfs_prefix++;
883 *(s - url_delim_len) = '\0';
884
885 vclass = vfs_prefix_to_class (vfs_prefix);
886 *(s - url_delim_len) = *VFS_PATH_URL_DELIMITER;
887
888 if (vclass != NULL && (vclass->flags & VFSF_REMOTE) != 0)
889 {
890 s = vfs_prefix;
891 continue;
892 }
893 }
894
895 if (IS_PATH_SEP (*s))
896 break;
897
898 s--;
899 }
900
901 s++;
902
903
904 if (s[0] == '.' && s[1] == '.' && s + 2 == p)
905 {
906 p += 3;
907 continue;
908 }
909
910 if (p[3] != '\0')
911 {
912 if (s == lpath && IS_PATH_SEP (*s))
913 {
914
915 str_move (s + 1, p + 4);
916 }
917 else
918 {
919
920 #ifdef HAVE_CHARSET
921 if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0)
922 && (is_supported_encoding (s + enc_prefix_len)))
923
924 str_move (s, p + 1);
925 else
926 #endif
927 str_move (s, p + 4);
928 }
929
930 p = s > lpath ? s - 1 : s;
931 continue;
932 }
933
934
935 if (s == lpath)
936 {
937
938 if (!IS_PATH_SEP (lpath[0]))
939 lpath[0] = '.';
940 lpath[1] = '\0';
941 }
942 else
943 {
944
945 if (s == lpath + 1)
946 s[0] = '\0';
947 #ifdef HAVE_CHARSET
948 else if ((strncmp (s, VFS_ENCODING_PREFIX, enc_prefix_len) == 0)
949 && (is_supported_encoding (s + enc_prefix_len)))
950 {
951
952 s[0] = '.';
953 s[1] = '.';
954 s[2] = '\0';
955
956
957
958 for (p = s - 1; p >= lpath && !IS_PATH_SEP (*p); p--)
959 ;
960
961 if (p >= lpath)
962 continue;
963 }
964 #endif
965 else
966 {
967 if (s >= lpath + url_delim_len
968 && strncmp (s - url_delim_len, VFS_PATH_URL_DELIMITER, url_delim_len) == 0)
969 *s = '\0';
970 else
971 s[-1] = '\0';
972 }
973 }
974
975 break;
976 }
977 }
978 }
979
980
981
982 void
983 canonicalize_pathname (char *path)
984 {
985 custom_canonicalize_pathname (path, CANON_PATH_ALL);
986 }
987
988
989
990 char *
991 mc_realpath (const char *path, char *resolved_path)
992 {
993 #ifdef HAVE_CHARSET
994 const char *p = path;
995 gboolean absolute_path = FALSE;
996
997 if (IS_PATH_SEP (*p))
998 {
999 absolute_path = TRUE;
1000 p++;
1001 }
1002
1003
1004 if (g_str_has_prefix (p, VFS_ENCODING_PREFIX))
1005 {
1006 p += strlen (VFS_ENCODING_PREFIX);
1007 p = strchr (p, PATH_SEP);
1008 if (p != NULL)
1009 {
1010 if (!absolute_path && p[1] != '\0')
1011 p++;
1012
1013 path = p;
1014 }
1015 }
1016 #endif
1017
1018 #ifdef HAVE_REALPATH
1019 return realpath (path, resolved_path);
1020 #else
1021 {
1022 char copy_path[PATH_MAX];
1023 char got_path[PATH_MAX];
1024 char *new_path = got_path;
1025 char *max_path;
1026 #ifdef S_IFLNK
1027 char link_path[PATH_MAX];
1028 int readlinks = 0;
1029 int n;
1030 #endif
1031
1032
1033 if (strlen (path) >= PATH_MAX - 2)
1034 {
1035 errno = ENAMETOOLONG;
1036 return NULL;
1037 }
1038
1039 strcpy (copy_path, path);
1040 path = copy_path;
1041 max_path = copy_path + PATH_MAX - 2;
1042
1043 if (!IS_PATH_SEP (*path))
1044 {
1045 new_path = g_get_current_dir ();
1046 if (new_path == NULL)
1047 strcpy (got_path, "");
1048 else
1049 {
1050 g_snprintf (got_path, sizeof (got_path), "%s", new_path);
1051 g_free (new_path);
1052 new_path = got_path;
1053 }
1054
1055 new_path += strlen (got_path);
1056 if (!IS_PATH_SEP (new_path[-1]))
1057 *new_path++ = PATH_SEP;
1058 }
1059 else
1060 {
1061 *new_path++ = PATH_SEP;
1062 path++;
1063 }
1064
1065 while (*path != '\0')
1066 {
1067
1068 if (IS_PATH_SEP (*path))
1069 {
1070 path++;
1071 continue;
1072 }
1073 if (*path == '.')
1074 {
1075
1076 if (path[1] == '\0' || IS_PATH_SEP (path[1]))
1077 {
1078 path++;
1079 continue;
1080 }
1081 if (path[1] == '.')
1082 {
1083 if (path[2] == '\0' || IS_PATH_SEP (path[2]))
1084 {
1085 path += 2;
1086
1087 if (new_path == got_path + 1)
1088 continue;
1089
1090 while (!IS_PATH_SEP ((--new_path)[-1]))
1091 ;
1092 continue;
1093 }
1094 }
1095 }
1096
1097 while (*path != '\0' && !IS_PATH_SEP (*path))
1098 {
1099 if (path > max_path)
1100 {
1101 errno = ENAMETOOLONG;
1102 return NULL;
1103 }
1104 *new_path++ = *path++;
1105 }
1106 #ifdef S_IFLNK
1107
1108 if (readlinks++ > MAXSYMLINKS)
1109 {
1110 errno = ELOOP;
1111 return NULL;
1112 }
1113
1114 *new_path = '\0';
1115 n = readlink (got_path, link_path, PATH_MAX - 1);
1116 if (n < 0)
1117 {
1118
1119 if (errno != EINVAL)
1120 {
1121
1122 *new_path = '\0';
1123 strcpy (resolved_path, got_path);
1124 return NULL;
1125 }
1126 }
1127 else
1128 {
1129
1130 link_path[n] = '\0';
1131 if (IS_PATH_SEP (*link_path))
1132
1133 new_path = got_path;
1134 else
1135
1136 while (!IS_PATH_SEP (*(--new_path)))
1137 ;
1138
1139 if (strlen (path) + n >= PATH_MAX - 2)
1140 {
1141 errno = ENAMETOOLONG;
1142 return NULL;
1143 }
1144
1145 strcat (link_path, path);
1146 strcpy (copy_path, link_path);
1147 path = copy_path;
1148 }
1149 #endif
1150 *new_path++ = PATH_SEP;
1151 }
1152
1153 if (new_path != got_path + 1 && IS_PATH_SEP (new_path[-1]))
1154 new_path--;
1155
1156 *new_path = '\0';
1157 strcpy (resolved_path, got_path);
1158 return resolved_path;
1159 }
1160 #endif
1161 }
1162
1163
1164
1165
1166
1167
1168
1169 int
1170 get_user_permissions (struct stat *st)
1171 {
1172 static gboolean initialized = FALSE;
1173 static gid_t *groups;
1174 static int ngroups;
1175 static uid_t uid;
1176 int i;
1177
1178 if (!initialized)
1179 {
1180 uid = geteuid ();
1181
1182 ngroups = getgroups (0, NULL);
1183 if (ngroups == -1)
1184 ngroups = 0;
1185
1186
1187
1188 groups = g_new (gid_t, ngroups + 1);
1189
1190 if (ngroups != 0)
1191 {
1192 ngroups = getgroups (ngroups, groups);
1193 if (ngroups == -1)
1194 ngroups = 0;
1195 }
1196
1197
1198
1199 groups[ngroups++] = getegid ();
1200
1201 initialized = TRUE;
1202 }
1203
1204 if (st->st_uid == uid || uid == 0)
1205 return 0;
1206
1207 for (i = 0; i < ngroups; i++)
1208 if (st->st_gid == groups[i])
1209 return 1;
1210
1211 return 2;
1212 }
1213
1214
1215
1216
1217
1218
1219
1220 char *
1221 mc_build_filenamev (const char *first_element, va_list args)
1222 {
1223 gboolean absolute;
1224 const char *element = first_element;
1225 GString *path;
1226 char *ret;
1227
1228 if (element == NULL)
1229 return NULL;
1230
1231 path = g_string_new ("");
1232
1233 absolute = IS_PATH_SEP (*first_element);
1234
1235 do
1236 {
1237 if (*element == '\0')
1238 element = va_arg (args, char *);
1239 else
1240 {
1241 char *tmp_element;
1242 size_t len;
1243 const char *start;
1244
1245 tmp_element = g_strdup (element);
1246
1247 element = va_arg (args, char *);
1248
1249 canonicalize_pathname (tmp_element);
1250 len = strlen (tmp_element);
1251 start = IS_PATH_SEP (tmp_element[0]) ? tmp_element + 1 : tmp_element;
1252
1253 g_string_append (path, start);
1254 if (!IS_PATH_SEP (tmp_element[len - 1]) && element != NULL)
1255 g_string_append_c (path, PATH_SEP);
1256
1257 g_free (tmp_element);
1258 }
1259 }
1260 while (element != NULL);
1261
1262 if (absolute)
1263 g_string_prepend_c (path, PATH_SEP);
1264
1265 ret = g_string_free (path, FALSE);
1266 canonicalize_pathname (ret);
1267
1268 return ret;
1269 }
1270
1271
1272
1273
1274
1275
1276
1277 char *
1278 mc_build_filename (const char *first_element, ...)
1279 {
1280 va_list args;
1281 char *ret;
1282
1283 if (first_element == NULL)
1284 return NULL;
1285
1286 va_start (args, first_element);
1287 ret = mc_build_filenamev (first_element, args);
1288 va_end (args);
1289 return ret;
1290 }
1291
1292