3 * Routines for handling path names.
6 * Gonzalo Paniagua Javier (gonzalo@novell.com)
7 * Miguel de Icaza (miguel@novell.com)
9 * (C) 2006 Novell, Inc. http://www.novell.com
20 /* This is only needed for the mono_path_canonicalize code, MAXSYMLINKS, could be moved */
21 #ifdef HAVE_SYS_PARAM_H
22 #include <sys/param.h>
25 #include "mono-path.h"
27 /* Embedded systems lack MAXSYMLINKS */
32 /* Resolves '..' and '.' references in a path. If the path provided is relative,
33 * it will be relative to the current directory */
35 /* For Native Client, the above is not true. Since there is no getcwd we fill */
36 /* in the file being passed in relative to '.' and don't resolve it */
38 /* There are a couple of tests for this method in mono/test/mono-path.cs */
40 mono_path_canonicalize (const char *path
)
42 gchar
*abspath
, *pos
, *lastpos
, *dest
;
45 if (g_path_is_absolute (path
)) {
46 abspath
= g_strdup (path
);
48 gchar
*tmpdir
= g_get_current_dir ();
49 abspath
= g_build_filename (tmpdir
, path
, NULL
);
54 g_strdelimit (abspath
, '/', '\\');
56 abspath
= g_strreverse (abspath
);
59 dest
= lastpos
= abspath
;
60 pos
= strchr (lastpos
, G_DIR_SEPARATOR
);
63 int len
= pos
- lastpos
;
64 if (len
== 1 && lastpos
[0] == '.') {
66 } else if (len
== 2 && lastpos
[0] == '.' && lastpos
[1] == '.') {
73 /* The two strings can overlap */
74 memmove (dest
, lastpos
, len
+ 1);
79 pos
= strchr (lastpos
, G_DIR_SEPARATOR
);
83 /* Avoid removing the first '\' for UNC paths. We must make sure that it's indeed an UNC path
84 by checking if the \\ pair happens exactly at the end of the string.
86 if (*(lastpos
-1) == G_DIR_SEPARATOR
&& *(lastpos
-2) == G_DIR_SEPARATOR
&& *lastpos
== 0)
90 if (dest
!= lastpos
) strcpy (dest
, lastpos
);
92 g_strreverse (abspath
);
94 /* We strip away all trailing dir separators. This is not correct for the root directory,
95 * since we'll return an empty string, so re-append a dir separator if there is none in the
97 if (strchr (abspath
, G_DIR_SEPARATOR
) == NULL
) {
98 int len
= strlen (abspath
);
99 abspath
= (gchar
*) g_realloc (abspath
, len
+ 2);
100 abspath
[len
] = G_DIR_SEPARATOR
;
108 * This ensures that the path that we store points to the final file
109 * not a path to a symlink.
111 #if !defined(HOST_NO_SYMLINKS)
113 resolve_symlink (const char *path
)
115 char *p
, *concat
, *dir
;
116 char buffer
[PATH_MAX
+1];
117 int n
, iterations
= 0;
122 n
= readlink (p
, buffer
, sizeof (buffer
)-1);
125 p
= mono_path_canonicalize (copy
);
131 if (!g_path_is_absolute (buffer
)) {
132 dir
= g_path_get_dirname (p
);
133 concat
= g_build_filename (dir
, buffer
, NULL
);
136 concat
= g_strdup (buffer
);
139 p
= mono_path_canonicalize (concat
);
141 } while (iterations
< MAXSYMLINKS
);
148 mono_path_resolve_symlinks (const char *path
)
150 #if defined(HOST_NO_SYMLINKS)
151 return mono_path_canonicalize (path
);
153 gchar
**split
= g_strsplit (path
, G_DIR_SEPARATOR_S
, -1);
154 gchar
*p
= g_strdup ("");
157 for (i
= 0; split
[i
] != NULL
; i
++) {
160 // resolve_symlink of "" goes into canonicalize which resolves to cwd
161 if (strcmp (split
[i
], "") != 0) {
162 tmp
= g_strdup_printf ("%s%s", p
, split
[i
]);
164 p
= resolve_symlink (tmp
);
168 if (split
[i
+1] != NULL
) {
169 tmp
= g_strdup_printf ("%s%s", p
, G_DIR_SEPARATOR_S
);
181 * mono_path_filename_in_basedir:
183 * Return \c TRUE if \p filename is in \p basedir
185 * Both paths must be absolute and using \c G_DIR_SEPARATOR for directory separators.
186 * If the file is in a subdirectory of \p basedir, returns \c FALSE.
187 * This function doesn't touch a filesystem, it looks solely at path names.
190 mono_path_filename_in_basedir (const char *filename
, const char *basedir
)
192 const char *p
= NULL
;
193 if ((p
= strstr (filename
, basedir
))) {
194 p
+= strlen (basedir
);
195 if (*p
!= G_DIR_SEPARATOR
)
197 /* if it's in a subdir of the basedir, it doesn't count. */
198 if (strchr (p
, G_DIR_SEPARATOR
))