New test.
[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 #include <unistd.h>
17 /* This is only needed for the mono_path_canonicalize code, MAXSYMLINKS, could be moved */
18 #include <sys/param.h>
19
20 #include "mono-path.h"
21
22 /* Resolves '..' and '.' references in a path. If the path provided is relative,
23  * it will be relative to the current directory */
24 gchar *
25 mono_path_canonicalize (const char *path)
26 {
27         gchar *abspath, *pos, *lastpos, *dest;
28         int backc;
29
30         if (g_path_is_absolute (path)) {
31                 abspath = g_strdup (path);
32         } else {
33                 gchar *tmpdir = g_get_current_dir ();
34                 abspath = g_build_filename (tmpdir, path, NULL);
35                 g_free (tmpdir);
36         }
37
38         abspath = g_strreverse (abspath);
39
40         backc = 0;
41         dest = lastpos = abspath;
42         pos = strchr (lastpos, G_DIR_SEPARATOR);
43
44         while (pos != NULL) {
45                 int len = pos - lastpos;
46                 if (len == 1 && lastpos [0] == '.') {
47                         // nop
48                 } else if (len == 2 && lastpos [0] == '.' && lastpos [1] == '.') {
49                         backc++;
50                 } else if (len > 0) {
51                         if (backc > 0) {
52                                 backc--;
53                         } else {
54                                 if (dest != lastpos) 
55                                         /* The two strings can overlap */
56                                         memmove (dest, lastpos, len + 1);
57                                 dest += len + 1;
58                         }
59                 }
60                 lastpos = pos + 1;
61                 pos = strchr (lastpos, G_DIR_SEPARATOR);
62         }
63         
64         if (dest != lastpos) strcpy (dest, lastpos);
65         return g_strreverse (abspath);
66 }
67
68 /*
69  * This ensures that the path that we store points to the final file
70  * not a path to a symlink.
71  */
72 gchar *
73 mono_path_resolve_symlinks (const char *path)
74 {
75 #if PLATFORM_WIN32
76         return mono_path_canonicalize (path);
77 #else
78         char *p, *concat, *dir;
79         char buffer [PATH_MAX+1];
80         int n, iterations = 0;
81
82         p = g_strdup (path);
83         do {
84                 iterations++;
85                 n = readlink (p, buffer, sizeof (buffer)-1);
86                 if (n < 0){
87                         char *copy = p;
88                         p = mono_path_canonicalize (copy);
89                         g_free (copy);
90                         return p;
91                 }
92                 
93                 buffer [n] = 0;
94                 if (!g_path_is_absolute (buffer)) {
95                         dir = g_path_get_dirname (p);
96                         concat = g_build_filename (dir, buffer, NULL);
97                         g_free (dir);
98                 } else {
99                         concat = g_strdup (buffer);
100                 }
101                 g_free (p);
102                 p = mono_path_canonicalize (concat);
103                 g_free (concat);
104         } while (iterations < MAXSYMLINKS);
105
106         return p;
107 #endif
108 }
109