common: Add functions make_absfilename and make_absfilename_try.

* common/stringhelp.c (do_make_filename): Add modes 2 and 3.
(make_absfilename): New.
(make_absfilename_try): New.
This commit is contained in:
Werner Koch 2014-04-15 16:40:48 +02:00
parent 1a87edab66
commit 71a54313ad
3 changed files with 174 additions and 2 deletions

View File

@ -1,6 +1,7 @@
/* stringhelp.c - standard string helper functions
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
* 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@ -49,9 +50,9 @@
#include "libjnlib-config.h"
#include "utf8conv.h"
#include "sysutils.h"
#include "stringhelp.h"
#define tohex_lower(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'a'))
/* Sometimes we want to avoid mixing slashes and backslashes on W32
@ -395,6 +396,12 @@ get_pwdir (int xmode, const char *name)
return result;
}
/* xmode 0 := Return NULL on error
1 := Terminate on error
2 := Make sure that name is absolute; return NULL on error
3 := Make sure that name is absolute; terminate on error
*/
static char *
do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
{
@ -404,6 +411,10 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
int skip = 1;
char *home_buffer = NULL;
char *name, *home, *p;
int want_abs;
want_abs = !!(xmode & 2);
xmode &= 1;
n = strlen (first_part) + 1;
argc = 0;
@ -478,10 +489,65 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
p = stpcpy (name, first_part);
jnlib_free (home_buffer);
for (argc=0; argv[argc]; argc++)
p = stpcpy (stpcpy (p, "/"), argv[argc]);
if (want_abs)
{
#ifdef HAVE_DRIVE_LETTERS
p = strchr (name, ':');
if (!p)
p = name;
#else
p = name;
#endif
if (*p != '/'
#ifdef HAVE_DRIVE_LETTERS
&& *p != '\\'
#endif
)
{
home = gnupg_getcwd ();
if (!home)
{
if (xmode)
{
fprintf (stderr, "\nfatal: getcwd failed: %s\n",
strerror (errno));
exit(2);
}
jnlib_free (name);
return NULL;
}
n = strlen (home) + 1 + strlen (name) + 1;
if (xmode)
home_buffer = jnlib_xmalloc (n);
else
{
home_buffer = jnlib_malloc (n);
if (!home_buffer)
{
jnlib_free (name);
return NULL;
}
}
if (p == name)
p = home_buffer;
else /* Windows case. */
{
memcpy (home_buffer, p, p - name + 1);
p = home_buffer + (p - name + 1);
}
strcpy (stpcpy (stpcpy (p, home), "/"), name);
jnlib_free (name);
name = home_buffer;
/* Let's do a simple compression to catch the most common
case of using "." for gpg's --homedir option. */
n = strlen (name);
if (n > 2 && name[n-2] == '/' && name[n-1] == '.')
name[n-2] = 0;
}
}
return change_slashes (name);
}
@ -515,6 +581,36 @@ make_filename_try (const char *first_part, ... )
return result;
}
/* Construct an absolute filename from the NULL terminated list of
parts. Tilde expansion is done for the first argument. This
function terminates the process on memory shortage. */
char *
make_absfilename (const char *first_part, ... )
{
va_list arg_ptr;
char *result;
va_start (arg_ptr, first_part);
result = do_make_filename (3, first_part, arg_ptr);
va_end (arg_ptr);
return result;
}
/* Construct an absolute filename from the NULL terminated list of
parts. Tilde expansion is done for the first argument. This
function may return NULL on error. */
char *
make_absfilename_try (const char *first_part, ... )
{
va_list arg_ptr;
char *result;
va_start (arg_ptr, first_part);
result = do_make_filename (2, first_part, arg_ptr);
va_end (arg_ptr);
return result;
}
/* Compare whether the filenames are identical. This is a

View File

@ -53,6 +53,9 @@ char *make_basename(const char *filepath, const char *inputpath);
char *make_dirname(const char *filepath);
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);
char *make_absfilename (const char *first_part, ...) GNUPG_GCC_A_SENTINEL(0);
char *make_absfilename_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

@ -71,6 +71,34 @@ gethome (void)
}
static char *
mygetcwd (void)
{
char *buffer;
size_t size = 100;
for (;;)
{
buffer = xmalloc (size+1);
#ifdef HAVE_W32CE_SYSTEM
strcpy (buffer, "/"); /* Always "/". */
return buffer;
#else
if (getcwd (buffer, size) == buffer)
return buffer;
xfree (buffer);
if (errno != ERANGE)
{
fprintf (stderr,"error getting current cwd: %s\n",
strerror (errno));
exit (2);
}
size *= 2;
#endif
}
}
static void
test_percent_escape (void)
{
@ -407,6 +435,50 @@ test_make_filename_try (void)
}
static void
test_make_absfilename_try (void)
{
char *out;
char *cwd = mygetcwd ();
size_t cwdlen = strlen (cwd);
out = make_absfilename_try ("foo", "bar", NULL);
if (!out)
fail (0);
if (strlen (out) < cwdlen + 7)
fail (0);
if (strncmp (out, cwd, cwdlen))
fail (0);
if (strcmp (out+cwdlen, "/foo/bar"))
fail (0);
xfree (out);
out = make_absfilename_try ("./foo", NULL);
if (!out)
fail (1);
if (strlen (out) < cwdlen + 5)
fail (1);
if (strncmp (out, cwd, cwdlen))
fail (1);
if (strcmp (out+cwdlen, "/./foo"))
fail (1);
xfree (out);
out = make_absfilename_try (".", NULL);
if (!out)
fail (2);
if (strlen (out) < cwdlen)
fail (2);
if (strncmp (out, cwd, cwdlen))
fail (2);
if (strcmp (out+cwdlen, ""))
fail (2);
xfree (out);
xfree (cwd);
}
int
main (int argc, char **argv)
{
@ -418,6 +490,7 @@ main (int argc, char **argv)
test_strconcat ();
test_xstrconcat ();
test_make_filename_try ();
test_make_absfilename_try ();
xfree (home_buffer);
return 0;