Mono runtime: Fix support for mixed-mode assemblies. Contributed under MIT/X11 license.
[mono.git] / mono / utils / mono-path.c
1 /*
2  * mono-path.c: Routines for handling path names.
3  * 
4  * Authors:
5  *      Gonzalo Paniagua Javier (gonzalo@novell.com)
6  *      Miguel de Icaza (miguel@novell.com)
7  *
8  * (C) 2006 Novell, Inc.  http://www.novell.com
9  *
10  */
11 #include <config.h>
12 #include <glib.h>
13 #include <errno.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #ifdef HAVE_UNISTD_H
17 #include <unistd.h>
18 #endif
19 /* This is only needed for the mono_path_canonicalize code, MAXSYMLINKS, could be moved */
20 #ifdef HAVE_SYS_PARAM_H
21 #include <sys/param.h>
22 #endif
23
24 #include "mono-path.h"
25
26 /* Resolves '..' and '.' references in a path. If the path provided is relative,
27  * it will be relative to the current directory */
28 gchar *
29 mono_path_canonicalize (const char *path)
30 {
31         gchar *abspath, *pos, *lastpos, *dest;
32         int backc;
33
34         if (g_path_is_absolute (path)) {
35                 abspath = g_strdup (path);
36         } else {
37                 gchar *tmpdir = g_get_current_dir ();
38                 abspath = g_build_filename (tmpdir, path, NULL);
39                 g_free (tmpdir);
40         }
41
42 #ifdef PLATFORM_WIN32
43         g_strdelimit (abspath, "/", '\\');
44 #endif
45         abspath = g_strreverse (abspath);
46
47         backc = 0;
48         dest = lastpos = abspath;
49         pos = strchr (lastpos, G_DIR_SEPARATOR);
50
51         while (pos != NULL) {
52                 int len = pos - lastpos;
53                 if (len == 1 && lastpos [0] == '.') {
54                         // nop
55                 } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') {
56                         backc++;
57                 } else if (len > 0) {
58                         if (backc > 0) {
59                                 backc--;
60                         } else {
61                                 if (dest != lastpos) 
62                                         /* The two strings can overlap */
63                                         memmove (dest, lastpos, len + 1);
64                                 dest += len + 1;
65                         }
66                 }
67                 lastpos = pos + 1;
68                 pos = strchr (lastpos, G_DIR_SEPARATOR);
69         }
70         
71         if (dest != lastpos) strcpy (dest, lastpos);
72         return g_strreverse (abspath);
73 }
74
75 /*
76  * This ensures that the path that we store points to the final file
77  * not a path to a symlink.
78  */
79 gchar *
80 mono_path_resolve_symlinks (const char *path)
81 {
82 #if PLATFORM_WIN32
83         return mono_path_canonicalize (path);
84 #else
85         char *p, *concat, *dir;
86         char buffer [PATH_MAX+1];
87         int n, iterations = 0;
88
89         p = g_strdup (path);
90         do {
91                 iterations++;
92                 n = readlink (p, buffer, sizeof (buffer)-1);
93                 if (n < 0){
94                         char *copy = p;
95                         p = mono_path_canonicalize (copy);
96                         g_free (copy);
97                         return p;
98                 }
99                 
100                 buffer [n] = 0;
101                 if (!g_path_is_absolute (buffer)) {
102                         dir = g_path_get_dirname (p);
103                         concat = g_build_filename (dir, buffer, NULL);
104                         g_free (dir);
105                 } else {
106                         concat = g_strdup (buffer);
107                 }
108                 g_free (p);
109                 p = mono_path_canonicalize (concat);
110                 g_free (concat);
111         } while (iterations < MAXSYMLINKS);
112
113         return p;
114 #endif
115 }
116