Merge branch '2372_mcedit_utf8_fix'
[midnight-commander.git] / lib / vfs / utilvfs.c
blob75682cd4c7ded8755ccf4dddee4df22a053bfeaf
1 /*
2 Utilities for VFS modules.
4 Copyright (C) 1988, 1992, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
5 2005, 2006, 2007, 2011
6 The Free Software Foundation, Inc.
8 Copyright (C) 1995, 1996 Miguel de Icaza
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
26 /**
27 * \file
28 * \brief Source: Utilities for VFS modules
29 * \author Miguel de Icaza
30 * \date 1995, 1996
33 #include <config.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <pwd.h>
38 #include <grp.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
43 #include "lib/global.h"
44 #include "lib/unixcompat.h"
45 #include "lib/util.h" /* mc_mkstemps() */
46 #include "lib/widget.h" /* message() */
48 #include "vfs.h"
49 #include "utilvfs.h"
51 /*** global variables ****************************************************************************/
53 /*** file scope macro definitions ****************************************************************/
55 #ifndef TUNMLEN
56 #define TUNMLEN 256
57 #endif
58 #ifndef TGNMLEN
59 #define TGNMLEN 256
60 #endif
62 #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
63 #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
65 #define MC_HISTORY_VFS_PASSWORD "mc.vfs.password"
67 /*** file scope type declarations ****************************************************************/
69 /*** file scope variables ************************************************************************/
71 /*** file scope functions ************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
75 /* --------------------------------------------------------------------------------------------- */
76 /*** public functions ****************************************************************************/
77 /* --------------------------------------------------------------------------------------------- */
78 /** Get current username
80 * @return g_malloc()ed string with the name of the currently logged in
81 * user ("anonymous" if uid is not registered in the system)
84 char *
85 vfs_get_local_username (void)
87 struct passwd *p_i;
89 p_i = getpwuid (geteuid ());
91 return (p_i && p_i->pw_name) ? g_strdup (p_i->pw_name) : g_strdup ("anonymous"); /* Unknown UID, strange */
94 /* --------------------------------------------------------------------------------------------- */
95 /**
96 * Look up a user or group name from a uid/gid, maintaining a cache.
97 * FIXME, for now it's a one-entry cache.
98 * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
99 * This file should be modified for non-unix systems to do something
100 * reasonable.
103 /* --------------------------------------------------------------------------------------------- */
106 vfs_finduid (const char *uname)
108 static int saveuid = -993;
109 static char saveuname[TUNMLEN];
110 static int my_uid = -993;
112 struct passwd *pw;
114 if (uname[0] != saveuname[0] /* Quick test w/o proc call */
115 || 0 != strncmp (uname, saveuname, TUNMLEN))
117 g_strlcpy (saveuname, uname, TUNMLEN);
118 pw = getpwnam (uname);
119 if (pw)
121 saveuid = pw->pw_uid;
123 else
125 saveuid = myuid;
128 return saveuid;
131 /* --------------------------------------------------------------------------------------------- */
134 vfs_findgid (const char *gname)
136 static int savegid = -993;
137 static char savegname[TGNMLEN];
138 static int my_gid = -993;
140 struct group *gr;
142 if (gname[0] != savegname[0] /* Quick test w/o proc call */
143 || 0 != strncmp (gname, savegname, TUNMLEN))
145 g_strlcpy (savegname, gname, TUNMLEN);
146 gr = getgrnam (gname);
147 if (gr)
149 savegid = gr->gr_gid;
151 else
153 savegid = mygid;
156 return savegid;
159 /* --------------------------------------------------------------------------------------------- */
161 * Create a temporary file with a name resembling the original.
162 * This is needed e.g. for local copies requested by extfs.
163 * Some extfs scripts may look at the extension.
164 * We also protect stupid scripts agains dangerous names.
168 vfs_mkstemps (char **pname, const char *prefix, const char *param_basename)
170 const char *p;
171 char *suffix, *q;
172 int shift;
173 int fd;
175 /* Strip directories */
176 p = strrchr (param_basename, PATH_SEP);
177 if (!p)
178 p = param_basename;
179 else
180 p++;
182 /* Protection against very long names */
183 shift = strlen (p) - (MC_MAXPATHLEN - 16);
184 if (shift > 0)
185 p += shift;
187 suffix = g_malloc (MC_MAXPATHLEN);
189 /* Protection against unusual characters */
190 q = suffix;
191 while (*p && (*p != '#'))
193 if (strchr (".-_@", *p) || isalnum ((unsigned char) *p))
194 *q++ = *p;
195 p++;
197 *q = 0;
199 fd = mc_mkstemps (pname, prefix, suffix);
200 g_free (suffix);
201 return fd;
204 /* --------------------------------------------------------------------------------------------- */
205 /** Extract the hostname and username from the path
207 * Format of the path is [user@]hostname:port/remote-dir, e.g.:
209 * ftp://sunsite.unc.edu/pub/linux
210 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
211 * ftp://tsx-11.mit.edu:8192/
212 * ftp://joe@foo.edu:11321/private
213 * ftp://joe:password@foo.se
215 * @param path is an input string to be parsed
216 * @param default_port is an input default port
217 * @param flags are parsing modifier flags (@see vfs_url_flags_t)
219 * @return g_malloc()ed url info.
220 * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
221 * is not set, then the current login name is supplied.
222 * Return value is a g_malloc()ed structure with the pathname relative to the
223 * host.
226 vfs_path_element_t *
227 vfs_url_split (const char *path, int default_port, vfs_url_flags_t flags)
229 vfs_path_element_t *path_element;
231 char *pcopy;
232 const char *pend;
233 char *dir, *colon, *inner_colon, *at, *rest;
235 path_element = g_new0 (vfs_path_element_t, 1);
236 path_element->port = default_port;
238 pcopy = g_strdup (path);
239 pend = pcopy + strlen (pcopy);
240 dir = pcopy;
242 if ((flags & URL_NOSLASH) == 0)
244 /* locate path component */
245 while (*dir != PATH_SEP && *dir != '\0')
246 dir++;
247 if (*dir == '\0')
248 path_element->path = g_strdup (PATH_SEP_STR);
249 else
251 path_element->path = g_strdup (dir);
252 *dir = '\0';
256 /* search for any possible user */
257 at = strrchr (pcopy, '@');
259 /* We have a username */
260 if (at == NULL)
261 rest = pcopy;
262 else
264 *at = '\0';
265 inner_colon = strchr (pcopy, ':');
266 if (inner_colon != NULL)
268 *inner_colon = '\0';
269 inner_colon++;
270 path_element->password = g_strdup (inner_colon);
273 if (*pcopy != '\0')
274 path_element->user = g_strdup (pcopy);
276 if (pend == at + 1)
277 rest = at;
278 else
279 rest = at + 1;
282 if ((flags & URL_USE_ANONYMOUS) == 0)
283 path_element->user = vfs_get_local_username ();
285 /* Check if the host comes with a port spec, if so, chop it */
286 if (*rest != '[')
287 colon = strchr (rest, ':');
288 else
290 colon = strchr (++rest, ']');
291 if (colon != NULL)
293 colon[0] = '\0';
294 colon[1] = '\0';
295 colon++;
297 else
299 vfs_path_element_free (path_element);
300 return NULL;
304 if (colon != NULL)
306 *colon = '\0';
307 if (sscanf (colon + 1, "%d", &path_element->port) == 1)
309 if (path_element->port <= 0 || path_element->port >= 65536)
310 path_element->port = default_port;
312 else
313 while (*(++colon) != '\0')
315 switch (*colon)
317 case 'C':
318 path_element->port = 1;
319 break;
320 case 'r':
321 path_element->port = 2;
322 break;
327 path_element->host = g_strdup (rest);
329 return path_element;
332 /* --------------------------------------------------------------------------------------------- */
334 void
335 vfs_die (const char *m)
337 message (D_ERROR, _("Internal error:"), "%s", m);
338 exit (EXIT_FAILURE);
341 /* --------------------------------------------------------------------------------------------- */
343 char *
344 vfs_get_password (const char *msg)
346 return input_dialog (msg, _("Password:"), MC_HISTORY_VFS_PASSWORD, INPUT_PASSWORD);
349 /* --------------------------------------------------------------------------------------------- */