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