1c9d5e7b1835977d1c38c2f4b72387d7f500ed3f
[midnight-commander.git] / lib / vfs / utilvfs.c
blob1c9d5e7b1835977d1c38c2f4b72387d7f500ed3f
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() */
47 #include "lib/strutil.h" /* INVALID_CONV */
49 #include "vfs.h"
50 #include "utilvfs.h"
52 /*** global variables ****************************************************************************/
54 /*** file scope macro definitions ****************************************************************/
56 #ifndef TUNMLEN
57 #define TUNMLEN 256
58 #endif
59 #ifndef TGNMLEN
60 #define TGNMLEN 256
61 #endif
63 #define myuid ( my_uid < 0? (my_uid = getuid()): my_uid )
64 #define mygid ( my_gid < 0? (my_gid = getgid()): my_gid )
66 #define MC_HISTORY_VFS_PASSWORD "mc.vfs.password"
68 /*** file scope type declarations ****************************************************************/
70 /*** file scope variables ************************************************************************/
72 /*** file scope functions ************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
76 /* --------------------------------------------------------------------------------------------- */
77 /*** public functions ****************************************************************************/
78 /* --------------------------------------------------------------------------------------------- */
79 /** Get current username
81 * @return g_malloc()ed string with the name of the currently logged in
82 * user ("anonymous" if uid is not registered in the system)
85 char *
86 vfs_get_local_username (void)
88 struct passwd *p_i;
90 p_i = getpwuid (geteuid ());
92 return (p_i && p_i->pw_name) ? g_strdup (p_i->pw_name) : g_strdup ("anonymous"); /* Unknown UID, strange */
95 /* --------------------------------------------------------------------------------------------- */
96 /**
97 * Look up a user or group name from a uid/gid, maintaining a cache.
98 * FIXME, for now it's a one-entry cache.
99 * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
100 * This file should be modified for non-unix systems to do something
101 * reasonable.
104 /* --------------------------------------------------------------------------------------------- */
107 vfs_finduid (const char *uname)
109 static int saveuid = -993;
110 static char saveuname[TUNMLEN];
111 static int my_uid = -993;
113 struct passwd *pw;
115 if (uname[0] != saveuname[0] /* Quick test w/o proc call */
116 || 0 != strncmp (uname, saveuname, TUNMLEN))
118 g_strlcpy (saveuname, uname, TUNMLEN);
119 pw = getpwnam (uname);
120 if (pw)
122 saveuid = pw->pw_uid;
124 else
126 saveuid = myuid;
129 return saveuid;
132 /* --------------------------------------------------------------------------------------------- */
135 vfs_findgid (const char *gname)
137 static int savegid = -993;
138 static char savegname[TGNMLEN];
139 static int my_gid = -993;
141 struct group *gr;
143 if (gname[0] != savegname[0] /* Quick test w/o proc call */
144 || 0 != strncmp (gname, savegname, TUNMLEN))
146 g_strlcpy (savegname, gname, TUNMLEN);
147 gr = getgrnam (gname);
148 if (gr)
150 savegid = gr->gr_gid;
152 else
154 savegid = mygid;
157 return savegid;
160 /* --------------------------------------------------------------------------------------------- */
162 * Create a temporary file with a name resembling the original.
163 * This is needed e.g. for local copies requested by extfs.
164 * Some extfs scripts may look at the extension.
165 * We also protect stupid scripts agains dangerous names.
169 vfs_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *param_basename)
171 const char *p;
172 char *suffix, *q;
173 int shift;
174 int fd;
176 /* Strip directories */
177 p = strrchr (param_basename, PATH_SEP);
178 if (!p)
179 p = param_basename;
180 else
181 p++;
183 /* Protection against very long names */
184 shift = strlen (p) - (MC_MAXPATHLEN - 16);
185 if (shift > 0)
186 p += shift;
188 suffix = g_malloc (MC_MAXPATHLEN);
190 /* Protection against unusual characters */
191 q = suffix;
192 while (*p && (*p != '#'))
194 if (strchr (".-_@", *p) || isalnum ((unsigned char) *p))
195 *q++ = *p;
196 p++;
198 *q = 0;
200 fd = mc_mkstemps (pname_vpath, prefix, suffix);
201 g_free (suffix);
202 return fd;
205 /* --------------------------------------------------------------------------------------------- */
206 /** Extract the hostname and username from the path
208 * Format of the path is [user@]hostname:port/remote-dir, e.g.:
210 * ftp://sunsite.unc.edu/pub/linux
211 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
212 * ftp://tsx-11.mit.edu:8192/
213 * ftp://joe@foo.edu:11321/private
214 * ftp://joe:password@foo.se
216 * @param path is an input string to be parsed
217 * @param default_port is an input default port
218 * @param flags are parsing modifier flags (@see vfs_url_flags_t)
220 * @return g_malloc()ed url info.
221 * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
222 * is not set, then the current login name is supplied.
223 * Return value is a g_malloc()ed structure with the pathname relative to the
224 * host.
227 vfs_path_element_t *
228 vfs_url_split (const char *path, int default_port, vfs_url_flags_t flags)
230 vfs_path_element_t *path_element;
232 char *pcopy;
233 size_t pcopy_len;
234 const char *pend;
235 char *dir, *colon, *inner_colon, *at, *rest;
237 path_element = g_new0 (vfs_path_element_t, 1);
238 path_element->port = default_port;
240 pcopy_len = strlen (path);
241 pcopy = g_strndup (path, pcopy_len);
242 pend = pcopy + pcopy_len;
243 dir = pcopy;
245 if ((flags & URL_NOSLASH) == 0)
247 /* locate path component */
248 while (*dir != PATH_SEP && *dir != '\0')
249 dir++;
250 if (*dir == '\0')
251 path_element->path = g_strdup (PATH_SEP_STR);
252 else
254 path_element->path = g_strndup (dir, pcopy_len - (size_t) (dir - pcopy));
255 *dir = '\0';
259 /* search for any possible user */
260 at = strrchr (pcopy, '@');
262 /* We have a username */
263 if (at == NULL)
264 rest = pcopy;
265 else
267 *at = '\0';
268 inner_colon = strchr (pcopy, ':');
269 if (inner_colon != NULL)
271 *inner_colon = '\0';
272 inner_colon++;
273 path_element->password = g_strdup (inner_colon);
276 if (*pcopy != '\0')
277 path_element->user = g_strdup (pcopy);
279 if (pend == at + 1)
280 rest = at;
281 else
282 rest = at + 1;
285 if ((flags & URL_USE_ANONYMOUS) == 0)
286 path_element->user = vfs_get_local_username ();
288 /* Check if the host comes with a port spec, if so, chop it */
289 if (*rest != '[')
290 colon = strchr (rest, ':');
291 else
293 colon = strchr (++rest, ']');
294 if (colon != NULL)
296 colon[0] = '\0';
297 colon[1] = '\0';
298 colon++;
300 else
302 vfs_path_element_free (path_element);
303 return NULL;
307 if (colon != NULL)
309 *colon = '\0';
310 if (sscanf (colon + 1, "%d", &path_element->port) == 1)
312 if (path_element->port <= 0 || path_element->port >= 65536)
313 path_element->port = default_port;
315 else
316 while (*(++colon) != '\0')
318 switch (*colon)
320 case 'C':
321 path_element->port = 1;
322 break;
323 case 'r':
324 path_element->port = 2;
325 break;
330 path_element->host = g_strdup (rest);
331 #ifdef HAVE_CHARSET
332 path_element->dir.converter = INVALID_CONV;
333 #endif
335 return path_element;
338 /* --------------------------------------------------------------------------------------------- */
340 void
341 vfs_die (const char *m)
343 message (D_ERROR, _("Internal error:"), "%s", m);
344 exit (EXIT_FAILURE);
347 /* --------------------------------------------------------------------------------------------- */
349 char *
350 vfs_get_password (const char *msg)
352 return input_dialog (msg, _("Password:"), MC_HISTORY_VFS_PASSWORD, INPUT_PASSWORD,
353 INPUT_COMPLETE_DEFAULT);
356 /* --------------------------------------------------------------------------------------------- */