(mc_search__recode_str): minor optimization.
[midnight-commander.git] / lib / vfs / utilvfs.c
blobbd5a410db5a219872d93c12dce4ff7f1738a22c9
1 /*
2 Utilities for VFS modules.
4 Copyright (C) 1988-2018
5 Free Software Foundation, Inc.
7 Copyright (C) 1995, 1996 Miguel de Icaza
9 This file is part of the Midnight Commander.
11 The Midnight Commander is free software: you can redistribute it
12 and/or modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation, either version 3 of the License,
14 or (at your option) any later version.
16 The Midnight Commander is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 /**
26 * \file
27 * \brief Source: Utilities for VFS modules
28 * \author Miguel de Icaza
29 * \date 1995, 1996
32 #include <config.h>
34 #include <ctype.h>
35 #include <sys/types.h>
36 #include <pwd.h>
37 #include <grp.h>
38 #include <stdlib.h>
39 #include <string.h>
41 #include "lib/global.h"
42 #include "lib/unixcompat.h"
43 #include "lib/util.h" /* mc_mkstemps() */
44 #include "lib/widget.h" /* message() */
45 #include "lib/strutil.h" /* INVALID_CONV */
47 #include "vfs.h"
48 #include "utilvfs.h"
50 /*** global variables ****************************************************************************/
52 /*** file scope macro definitions ****************************************************************/
54 #ifndef TUNMLEN
55 #define TUNMLEN 256
56 #endif
57 #ifndef TGNMLEN
58 #define TGNMLEN 256
59 #endif
61 #define MC_HISTORY_VFS_PASSWORD "mc.vfs.password"
64 * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
66 #define GUID_DEFAULT_CONST -993
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 * 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 = GUID_DEFAULT_CONST;
109 static char saveuname[TUNMLEN] = "\0";
111 if (uname[0] != saveuname[0] /* Quick test w/o proc call */
112 || 0 != strncmp (uname, saveuname, TUNMLEN))
114 struct passwd *pw;
116 g_strlcpy (saveuname, uname, TUNMLEN);
117 pw = getpwnam (uname);
118 if (pw)
120 saveuid = pw->pw_uid;
122 else
124 static int my_uid = GUID_DEFAULT_CONST;
126 if (my_uid < 0)
127 my_uid = getuid ();
129 saveuid = my_uid;
132 return saveuid;
135 /* --------------------------------------------------------------------------------------------- */
138 vfs_findgid (const char *gname)
140 static int savegid = GUID_DEFAULT_CONST;
141 static char savegname[TGNMLEN] = "\0";
144 if (gname[0] != savegname[0] /* Quick test w/o proc call */
145 || 0 != strncmp (gname, savegname, TUNMLEN))
147 struct group *gr;
149 g_strlcpy (savegname, gname, TUNMLEN);
150 gr = getgrnam (gname);
151 if (gr)
153 savegid = gr->gr_gid;
155 else
157 static int my_gid = GUID_DEFAULT_CONST;
159 if (my_gid < 0)
160 my_gid = getgid ();
162 savegid = my_gid;
165 return savegid;
168 /* --------------------------------------------------------------------------------------------- */
170 * Create a temporary file with a name resembling the original.
171 * This is needed e.g. for local copies requested by extfs.
172 * Some extfs scripts may look at the extension.
173 * We also protect stupid scripts agains dangerous names.
177 vfs_mkstemps (vfs_path_t ** pname_vpath, const char *prefix, const char *param_basename)
179 const char *p;
180 GString *suffix;
181 int shift;
182 int fd;
184 /* Strip directories */
185 p = strrchr (param_basename, PATH_SEP);
186 if (p == NULL)
187 p = param_basename;
188 else
189 p++;
191 /* Protection against very long names */
192 shift = strlen (p) - (MC_MAXPATHLEN - 16);
193 if (shift > 0)
194 p += shift;
196 suffix = g_string_sized_new (32);
198 /* Protection against unusual characters */
199 for (; *p != '\0' && *p != '#'; p++)
200 if (strchr (".-_@", *p) != NULL || g_ascii_isalnum (*p))
201 g_string_append_c (suffix, *p);
203 fd = mc_mkstemps (pname_vpath, prefix, suffix->str);
204 g_string_free (suffix, TRUE);
206 return fd;
209 /* --------------------------------------------------------------------------------------------- */
210 /** Extract the hostname and username from the path
212 * Format of the path is [user@]hostname:port/remote-dir, e.g.:
214 * ftp://sunsite.unc.edu/pub/linux
215 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
216 * ftp://tsx-11.mit.edu:8192/
217 * ftp://joe@foo.edu:11321/private
218 * ftp://joe:password@foo.se
220 * @param path is an input string to be parsed
221 * @param default_port is an input default port
222 * @param flags are parsing modifier flags (@see vfs_url_flags_t)
224 * @return g_malloc()ed url info.
225 * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
226 * is not set, then the current login name is supplied.
227 * Return value is a g_malloc()ed structure with the pathname relative to the
228 * host.
231 vfs_path_element_t *
232 vfs_url_split (const char *path, int default_port, vfs_url_flags_t flags)
234 vfs_path_element_t *path_element;
236 char *pcopy;
237 size_t pcopy_len;
238 const char *pend;
239 char *colon, *at, *rest;
241 path_element = g_new0 (vfs_path_element_t, 1);
242 path_element->port = default_port;
244 pcopy_len = strlen (path);
245 pcopy = g_strndup (path, pcopy_len);
246 pend = pcopy + pcopy_len;
248 if ((flags & URL_NOSLASH) == 0)
250 char *dir = pcopy;
252 /* locate path component */
253 while (!IS_PATH_SEP (*dir) && *dir != '\0')
254 dir++;
255 if (*dir == '\0')
256 path_element->path = g_strdup (PATH_SEP_STR);
257 else
259 path_element->path = g_strndup (dir, pcopy_len - (size_t) (dir - pcopy));
260 *dir = '\0';
264 /* search for any possible user */
265 at = strrchr (pcopy, '@');
267 /* We have a username */
268 if (at == NULL)
269 rest = pcopy;
270 else
272 char *inner_colon;
274 *at = '\0';
275 inner_colon = strchr (pcopy, ':');
276 if (inner_colon != NULL)
278 *inner_colon = '\0';
279 inner_colon++;
280 path_element->password = g_strdup (inner_colon);
283 if (*pcopy != '\0')
284 path_element->user = g_strdup (pcopy);
286 if (pend == at + 1)
287 rest = at;
288 else
289 rest = at + 1;
292 if ((flags & URL_USE_ANONYMOUS) == 0)
294 g_free (path_element->user);
295 path_element->user = vfs_get_local_username ();
297 /* Check if the host comes with a port spec, if so, chop it */
298 if (*rest != '[')
299 colon = strchr (rest, ':');
300 else
302 colon = strchr (++rest, ']');
303 if (colon != NULL)
305 colon[0] = '\0';
306 colon[1] = '\0';
307 colon++;
309 else
311 vfs_path_element_free (path_element);
312 g_free (pcopy);
313 return NULL;
317 if (colon != NULL)
319 *colon = '\0';
320 /* cppcheck-suppress invalidscanf */
321 if (sscanf (colon + 1, "%d", &path_element->port) == 1)
323 if (path_element->port <= 0 || path_element->port >= 65536)
324 path_element->port = default_port;
326 else
327 while (*(++colon) != '\0')
329 switch (*colon)
331 case 'C':
332 path_element->port = 1;
333 break;
334 case 'r':
335 path_element->port = 2;
336 break;
337 default:
338 break;
343 path_element->host = g_strdup (rest);
344 g_free (pcopy);
345 #ifdef HAVE_CHARSET
346 path_element->dir.converter = INVALID_CONV;
347 #endif
349 return path_element;
352 /* --------------------------------------------------------------------------------------------- */
354 void __attribute__ ((noreturn)) vfs_die (const char *m)
356 message (D_ERROR, _("Internal error:"), "%s", m);
357 exit (EXIT_FAILURE);
360 /* --------------------------------------------------------------------------------------------- */
362 char *
363 vfs_get_password (const char *msg)
365 return input_dialog (msg, _("Password:"), MC_HISTORY_VFS_PASSWORD, INPUT_PASSWORD,
366 INPUT_COMPLETE_NONE);
369 /* --------------------------------------------------------------------------------------------- */