[xbuild] Fix assembly name comparison when resolving references.
[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 /* Embedded systems lack MAXSYMLINKS */
27 #ifndef MAXSYMLINKS
28 #define MAXSYMLINKS 3
29 #endif
30
31 /* Resolves '..' and '.' references in a path. If the path provided is relative,
32  * it will be relative to the current directory */
33
34 /* For Native Client, the above is not true.  Since there is no getcwd we fill */
35 /* in the file being passed in relative to '.' and don't resolve it            */
36 gchar *
37 mono_path_canonicalize (const char *path)
38 {
39         gchar *abspath, *pos, *lastpos, *dest;
40         int backc;
41
42         if (g_path_is_absolute (path)) {
43                 abspath = g_strdup (path);
44         } else {
45 #ifdef __native_client__
46                 gchar *tmpdir = ".";
47                 abspath = g_build_filename (tmpdir, path, NULL);
48 #else
49                 gchar *tmpdir = g_get_current_dir ();
50                 abspath = g_build_filename (tmpdir, path, NULL);
51                 g_free (tmpdir);
52 #endif
53         }
54
55 #ifdef HOST_WIN32
56         g_strdelimit (abspath, "/", '\\');
57 #endif
58         abspath = g_strreverse (abspath);
59
60         backc = 0;
61         dest = lastpos = abspath;
62         pos = strchr (lastpos, G_DIR_SEPARATOR);
63
64         while (pos != NULL) {
65                 int len = pos - lastpos;
66                 if (len == 1 && lastpos [0] == '.') {
67                         // nop
68                 } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') {
69                         backc++;
70                 } else if (len > 0) {
71                         if (backc > 0) {
72                                 backc--;
73                         } else {
74                                 if (dest != lastpos) 
75                                         /* The two strings can overlap */
76                                         memmove (dest, lastpos, len + 1);
77                                 dest += len + 1;
78                         }
79                 }
80                 lastpos = pos + 1;
81                 pos = strchr (lastpos, G_DIR_SEPARATOR);
82         }
83
84 #ifdef HOST_WIN32 /* For UNC paths the first '\' is removed. */
85         if (*(lastpos-1) == G_DIR_SEPARATOR && *(lastpos-2) == G_DIR_SEPARATOR)
86                 lastpos = lastpos-1;
87 #endif
88         
89         if (dest != lastpos) strcpy (dest, lastpos);
90         return g_strreverse (abspath);
91 }
92
93 /*
94  * This ensures that the path that we store points to the final file
95  * not a path to a symlink.
96  */
97 #if !defined(PLATFORM_NO_SYMLINKS)
98 static gchar *
99 resolve_symlink (const char *path)
100 {
101         char *p, *concat, *dir;
102         char buffer [PATH_MAX+1];
103         int n, iterations = 0;
104
105         p = g_strdup (path);
106         do {
107                 iterations++;
108                 n = readlink (p, buffer, sizeof (buffer)-1);
109                 if (n < 0){
110                         char *copy = p;
111                         p = mono_path_canonicalize (copy);
112                         g_free (copy);
113                         return p;
114                 }
115                 
116                 buffer [n] = 0;
117                 if (!g_path_is_absolute (buffer)) {
118                         dir = g_path_get_dirname (p);
119                         concat = g_build_filename (dir, buffer, NULL);
120                         g_free (dir);
121                 } else {
122                         concat = g_strdup (buffer);
123                 }
124                 g_free (p);
125                 p = mono_path_canonicalize (concat);
126                 g_free (concat);
127         } while (iterations < MAXSYMLINKS);
128
129         return p;
130 }
131 #endif
132
133 gchar *
134 mono_path_resolve_symlinks (const char *path)
135 {
136 #if defined(PLATFORM_NO_SYMLINKS)
137         return mono_path_canonicalize (path);
138 #else
139         gchar **split = g_strsplit (path, G_DIR_SEPARATOR_S, -1);
140         gchar *p = g_strdup ("");
141         int i;
142
143         for (i = 0; split [i] != NULL; i++) {
144                 gchar *tmp = NULL;
145
146                 // resolve_symlink of "" goes into canonicalize which resolves to cwd
147                 if (strcmp (split [i], "") != 0) {
148                         tmp = g_strdup_printf ("%s%s", p, split [i]);
149                         g_free (p);
150                         p = resolve_symlink (tmp);
151                         g_free (tmp);
152                 }
153
154                 if (split [i+1] != NULL) {
155                         tmp = g_strdup_printf ("%s%s", p, G_DIR_SEPARATOR_S);
156                         g_free (p);
157                         p = tmp;
158                 }
159         }
160
161         g_strfreev (split);
162         return p;
163 #endif
164 }
165