Remove unneeded `struct` keyword for typedef'd structs
[midnight-commander.git] / lib / vfs / utilvfs.c
blob6b6ef387a0ae798700fd060d4a96bb31258f11db
1 /*
2 Utilities for VFS modules.
4 Copyright (C) 1988-2016
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 char *suffix, *q;
181 int shift;
182 int fd;
184 /* Strip directories */
185 p = strrchr (param_basename, PATH_SEP);
186 if (!p)
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_malloc (MC_MAXPATHLEN);
198 /* Protection against unusual characters */
199 q = suffix;
200 while (*p && (*p != '#'))
202 if (strchr (".-_@", *p) || isalnum ((unsigned char) *p))
203 *q++ = *p;
204 p++;
206 *q = 0;
208 fd = mc_mkstemps (pname_vpath, prefix, suffix);
209 g_free (suffix);
210 return fd;
213 /* --------------------------------------------------------------------------------------------- */
214 /** Extract the hostname and username from the path
216 * Format of the path is [user@]hostname:port/remote-dir, e.g.:
218 * ftp://sunsite.unc.edu/pub/linux
219 * ftp://miguel@sphinx.nuclecu.unam.mx/c/nc
220 * ftp://tsx-11.mit.edu:8192/
221 * ftp://joe@foo.edu:11321/private
222 * ftp://joe:password@foo.se
224 * @param path is an input string to be parsed
225 * @param default_port is an input default port
226 * @param flags are parsing modifier flags (@see vfs_url_flags_t)
228 * @return g_malloc()ed url info.
229 * If the user is empty, e.g. ftp://@roxanne/private, and URL_USE_ANONYMOUS
230 * is not set, then the current login name is supplied.
231 * Return value is a g_malloc()ed structure with the pathname relative to the
232 * host.
235 vfs_path_element_t *
236 vfs_url_split (const char *path, int default_port, vfs_url_flags_t flags)
238 vfs_path_element_t *path_element;
240 char *pcopy;
241 size_t pcopy_len;
242 const char *pend;
243 char *dir, *colon, *at, *rest;
245 path_element = g_new0 (vfs_path_element_t, 1);
246 path_element->port = default_port;
248 pcopy_len = strlen (path);
249 pcopy = g_strndup (path, pcopy_len);
250 pend = pcopy + pcopy_len;
251 dir = pcopy;
253 if ((flags & URL_NOSLASH) == 0)
255 /* locate path component */
256 while (!IS_PATH_SEP (*dir) && *dir != '\0')
257 dir++;
258 if (*dir == '\0')
259 path_element->path = g_strdup (PATH_SEP_STR);
260 else
262 path_element->path = g_strndup (dir, pcopy_len - (size_t) (dir - pcopy));
263 *dir = '\0';
267 /* search for any possible user */
268 at = strrchr (pcopy, '@');
270 /* We have a username */
271 if (at == NULL)
272 rest = pcopy;
273 else
275 char *inner_colon;
277 *at = '\0';
278 inner_colon = strchr (pcopy, ':');
279 if (inner_colon != NULL)
281 *inner_colon = '\0';
282 inner_colon++;
283 path_element->password = g_strdup (inner_colon);
286 if (*pcopy != '\0')
287 path_element->user = g_strdup (pcopy);
289 if (pend == at + 1)
290 rest = at;
291 else
292 rest = at + 1;
295 if ((flags & URL_USE_ANONYMOUS) == 0)
296 path_element->user = vfs_get_local_username ();
298 /* Check if the host comes with a port spec, if so, chop it */
299 if (*rest != '[')
300 colon = strchr (rest, ':');
301 else
303 colon = strchr (++rest, ']');
304 if (colon != NULL)
306 colon[0] = '\0';
307 colon[1] = '\0';
308 colon++;
310 else
312 vfs_path_element_free (path_element);
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 #ifdef HAVE_CHARSET
345 path_element->dir.converter = INVALID_CONV;
346 #endif
348 return path_element;
351 /* --------------------------------------------------------------------------------------------- */
353 void
354 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 /* --------------------------------------------------------------------------------------------- */