Implement tilde expansion in the same was as 1.4.

This commit is contained in:
Werner Koch 2009-08-26 08:55:57 +00:00
parent f816bdb381
commit 5134fee5b0
5 changed files with 300 additions and 46 deletions

View File

@ -1,3 +1,15 @@
2009-08-26 Werner Koch <wk@g10code.com>
* stringhelp.c [HAVE_PWD_H]: Include pwd.h.
(do_make_filename): New.
(make_filename, make_filename_try): Implement using the new
function.
* t-stringhelp.c (test_make_filename_try): New.
* t-support.c (gcry_strdup): Fix.
* stringhelp.h (make_filename, make_filename_try): Add sentinel
attribute.
2009-08-25 Werner Koch <wk@g10code.com>
* stringhelp.c: Include errno.h.

View File

@ -24,8 +24,13 @@
#include <stdarg.h>
#include <ctype.h>
#include <errno.h>
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#ifdef HAVE_W32_SYSTEM
#include <windows.h>
# include <windows.h>
#endif
#include "libjnlib-config.h"
@ -313,62 +318,159 @@ make_dirname(const char *filepath)
/* Implementation of make_filename and make_filename_try. We need to
use macros here to avoid the use of the sometimes problematic
va_copy function which is not available on all systems. */
#define MAKE_FILENAME_PART1 \
va_list arg_ptr; \
size_t n; \
const char *s; \
char *name, *home, *p; \
\
va_start (arg_ptr, first_part); \
n = strlen (first_part) + 1; \
while ( (s = va_arg (arg_ptr, const char *)) ) \
n += strlen(s) + 1; \
va_end(arg_ptr); \
\
home = NULL; \
if ( *first_part == '~' && first_part[1] == '/' \
&& (home = getenv("HOME")) && *home ) \
n += strlen (home);
static char *
do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
{
const char *argv[32];
int argc;
size_t n;
int skip = 1;
char *home_buffer = NULL;
char *name, *home, *p;
n = strlen (first_part) + 1;
argc = 0;
while ( (argv[argc] = va_arg (arg_ptr, const char *)) )
{
n += strlen (argv[argc]) + 1;
if (argc >= DIM (argv)-1)
{
if (xmode)
BUG ();
errno = EINVAL;
return NULL;
}
argc++;
}
n++;
#define MAKE_FILENAME_PART2 \
p = (home \
? stpcpy (stpcpy (name,home), first_part + 1)\
: stpcpy(name, first_part)); \
\
va_start (arg_ptr, first_part); \
while ( (s = va_arg(arg_ptr, const char *)) ) \
p = stpcpy (stpcpy (p,"/"), s); \
va_end(arg_ptr); \
return change_slashes (name);
home = NULL;
if (*first_part == '~')
{
if (first_part[1] == '/' || !first_part[1])
{
/* This is the "~/" or "~" case. */
home = getenv("HOME");
#if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
if (!home)
{
struct passwd *pwd;
pwd = getpwuid (getuid());
if (pwd)
{
if (xmode)
home_buffer = home = jnlib_xstrdup (pwd->pw_dir);
else
{
home_buffer = home = jnlib_strdup (pwd->pw_dir);
if (!home)
return NULL;
}
}
}
#endif /* HAVE_GETPWUID && HAVE_PWD_H */
if (home && *home)
n += strlen (home);
}
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
else
{
/* This is the "~username/" or "~username" case. */
char *user;
struct passwd *pwd;
if (xmode)
user = jnlib_xstrdup (first_part+1);
else
{
user = jnlib_strdup (first_part+1);
if (!user)
return NULL;
}
p = strchr (user, '/');
if (p)
*p = 0;
skip = 1 + strlen (user);
/* Fixme: Use getwpnam_r if available. */
pwd = getpwnam (user);
jnlib_free (user);
if (pwd)
{
if (xmode)
home_buffer = home = jnlib_xstrdup (pwd->pw_dir);
else
{
home_buffer = home = jnlib_strdup (pwd->pw_dir);
if (!home)
return NULL;
}
}
if (home)
n += strlen (home);
else
skip = 1;
}
#endif /*HAVE_GETPWNAM && HAVE_PWD_H*/
}
if (xmode)
name = jnlib_xmalloc (n);
else
{
name = jnlib_malloc (n);
if (!name)
{
jnlib_free (home_buffer);
return NULL;
}
}
if (home)
p = stpcpy (stpcpy (name, home), first_part + skip);
else
p = stpcpy (name, first_part);
jnlib_free (home_buffer);
for (argc=0; argv[argc]; argc++)
p = stpcpy (stpcpy (p, "/"), argv[argc]);
return change_slashes (name);
}
/* Construct a filename from the NULL terminated list of parts. Tilde
expansion is done here. This function terminates the process on
memory shortage. */
expansion is done for the first argument. This function terminates
the process on memory shortage. */
char *
make_filename (const char *first_part, ... )
{
MAKE_FILENAME_PART1
name = jnlib_xmalloc (n);
MAKE_FILENAME_PART2
va_list arg_ptr;
char *result;
va_start (arg_ptr, first_part);
result = do_make_filename (1, first_part, arg_ptr);
va_end (arg_ptr);
return result;
}
/* Construct a filename from the NULL terminated list of parts. Tilde
expansion is done here. This function may return NULL on error. */
expansion is done for the first argument. This function may return
NULL on error. */
char *
make_filename_try (const char *first_part, ... )
{
MAKE_FILENAME_PART1
name = jnlib_malloc (n);
if (!name)
return NULL;
MAKE_FILENAME_PART2
va_list arg_ptr;
char *result;
va_start (arg_ptr, first_part);
result = do_make_filename (0, first_part, arg_ptr);
va_end (arg_ptr);
return result;
}
#undef MAKE_FILENAME_PART1
#undef MAKE_FILENAME_PART2

View File

@ -37,8 +37,8 @@ size_t length_sans_trailing_ws (const unsigned char *line, size_t len);
char *make_basename(const char *filepath, const char *inputpath);
char *make_dirname(const char *filepath);
char *make_filename( const char *first_part, ... );
char *make_filename_try (const char *first_part, ... );
char *make_filename( const char *first_part, ... ) GNUPG_GCC_A_SENTINEL(0);
char *make_filename_try (const char *first_part, ... ) GNUPG_GCC_A_SENTINEL(0);
int compare_filenames( const char *a, const char *b );
int hextobyte (const char *s);

View File

@ -22,12 +22,43 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#include <unistd.h>
#include <sys/types.h>
#include "stringhelp.h"
#include "t-support.h"
static char *home_buffer;
const char *
gethome (void)
{
if (!home_buffer)
{
char *home = getenv("HOME");
#if defined(HAVE_GETPWUID) && defined(HAVE_PWD_H)
if(home)
home_buffer = xstrdup (home);
else
{
struct passwd *pwd;
pwd = getpwuid (getuid());
if (pwd)
home_buffer = xstrdup (pwd->pw_dir);
}
#endif
}
return home_buffer;
}
static void
test_percent_escape (void)
@ -261,6 +292,110 @@ test_xstrconcat (void)
}
static void
test_make_filename_try (void)
{
char *out;
const char *home = gethome ();
size_t homelen = home? strlen (home):0;
out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", NULL);
if (out)
fail (0);
else if (errno != EINVAL)
fail (0);
xfree (out);
out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", NULL);
if (out)
fail (0);
else if (errno != EINVAL)
fail (0);
xfree (out);
out = make_filename_try ("1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
"1", "2", NULL);
if (!out || strcmp (out,
"1/2/3/4/5/6/7/8/9/10/"
"1/2/3/4/5/6/7/8/9/10/"
"1/2/3/4/5/6/7/8/9/10/"
"1/2"))
fail (0);
xfree (out);
out = make_filename_try ("foo", "~/bar", "baz/cde", NULL);
if (!out || strcmp (out, "foo/~/bar/baz/cde"))
fail (1);
xfree (out);
out = make_filename_try ("foo", "~/bar", "baz/cde/", NULL);
if (!out || strcmp (out, "foo/~/bar/baz/cde/"))
fail (1);
xfree (out);
out = make_filename_try ("/foo", "~/bar", "baz/cde/", NULL);
if (!out || strcmp (out, "/foo/~/bar/baz/cde/"))
fail (1);
xfree (out);
out = make_filename_try ("//foo", "~/bar", "baz/cde/", NULL);
if (!out || strcmp (out, "//foo/~/bar/baz/cde/"))
fail (1);
xfree (out);
out = make_filename_try ("", "~/bar", "baz/cde", NULL);
if (!out || strcmp (out, "/~/bar/baz/cde"))
fail (1);
xfree (out);
out = make_filename_try ("~/foo", "bar", NULL);
if (!out)
fail (2);
if (home)
{
if (strlen (out) < homelen + 7)
fail (2);
if (strncmp (out, home, homelen))
fail (2);
if (strcmp (out+homelen, "/foo/bar"))
fail (2);
}
else
{
if (strcmp (out, "~/foo/bar"))
fail (2);
}
xfree (out);
out = make_filename_try ("~", "bar", NULL);
if (!out)
fail (2);
if (home)
{
if (strlen (out) < homelen + 3)
fail (2);
if (strncmp (out, home, homelen))
fail (2);
if (strcmp (out+homelen, "/bar"))
fail (2);
}
else
{
if (strcmp (out, "~/bar"))
fail (2);
}
xfree (out);
}
int
main (int argc, char **argv)
{
@ -271,7 +406,9 @@ main (int argc, char **argv)
test_compare_filenames ();
test_strconcat ();
test_xstrconcat ();
test_make_filename_try ();
xfree (home_buffer);
return 0;
}

View File

@ -56,7 +56,10 @@ gcry_xmalloc (size_t n)
char *
gcry_strdup (const char *string)
{
return malloc (strlen (string)+1);
char *p = malloc (strlen (string)+1);
if (p)
strcpy (p, string);
return p;
}