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