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