aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-02-18 07:53:30 +0000
committerWerner Koch <[email protected]>2020-02-18 07:56:33 +0000
commit5742b8eaf3fa9cda3dfb6b3ad0fea7485fff1a12 (patch)
tree7bb1347295569e10184f65ccfb3aea8e44495275 /src
parentw32: Support static link with -lws2_32. (diff)
downloadlibgpg-error-5742b8eaf3fa9cda3dfb6b3ad0fea7485fff1a12.tar.gz
libgpg-error-5742b8eaf3fa9cda3dfb6b3ad0fea7485fff1a12.zip
core: Add gpgrt_fnameconcat and gpgrt_absfnameconcat.
* src/gpg-error.h.in (gpgrt_fnameconcat): New. (gpgrt_absfnameconcat): New. * src/visibility.c (gpgrt_fnameconcat, gpgrt_absfnameconcat): New. * src/stringutils.c: New file. (_gpgrt_vfnameconcat): New. (_gpgrt_fnameconcat, _gpgrt_absfnameconcat): New. * src/gpg-error.def.in: Add new functions. * src/gpg-error.vers: Ditto. * src/sysutils.c: Include pwd.h. (_gpgrt_getpwdir): New. * configure.ac: Test for pwd.h, getpwnam, getpwuid, and their _r variants. * src/Makefile.am (libgpg_error_la_SOURCES): Add new file. * tests/t-stringutils.c: New. * tests/t-common.h (xmalloc, xstrdup, xfree): New. (die): Kludge to avoid compiler warnings. -- The new functions are based on the code of make_filename from GnuPG. They have been written by me ages ago with only minor modifications by David Shaw. I re-license them from LGPL-3.0+ OR GPL-2.0+ to LGPL-2.1-or-later. Signed-off-by: Werner Koch <[email protected]>
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/gpg-error.def.in3
-rw-r--r--src/gpg-error.h.in6
-rw-r--r--src/gpg-error.vers3
-rw-r--r--src/gpgrt-int.h11
-rw-r--r--src/stringutils.c224
-rw-r--r--src/sysutils.c39
-rw-r--r--src/visibility.c27
-rw-r--r--src/visibility.h4
9 files changed, 318 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e9c057f..336fe2a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -198,6 +198,7 @@ libgpg_error_la_SOURCES = gettext.h $(arch_sources) \
strsource.c strerror.c code-to-errno.c code-from-errno.c \
visibility.c visibility.h \
sysutils.c \
+ stringutils.c \
syscall-clamp.c \
logging.c \
b64dec.c b64enc.c \
diff --git a/src/gpg-error.def.in b/src/gpg-error.def.in
index 0a584c4..4e3b5d7 100644
--- a/src/gpg-error.def.in
+++ b/src/gpg-error.def.in
@@ -229,4 +229,7 @@ EXPORTS
gpgrt_add_emergency_cleanup @174
gpgrt_abort @175
+ gpgrt_fnameconcat @178
+ gpgrt_absfnameconcat @179
+
;; end of file with public symbols for Windows.
diff --git a/src/gpg-error.h.in b/src/gpg-error.h.in
index d118e90..470021d 100644
--- a/src/gpg-error.h.in
+++ b/src/gpg-error.h.in
@@ -1309,6 +1309,12 @@ void gpgrt_set_fixed_string_mapper (const char *(*f)(const char*));
* numbering scheme a LEVEL of 3 is suitable; see the manual. */
int gpgrt_cmp_version (const char *a, const char *b, int level);
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ * expansion is done for the first argument. The caller must release
+ * the result using gpgrt_free; on error ERRNO is set and NULL
+ * returned. The second function returns an absolute filename. */
+char *gpgrt_fnameconcat (const char *first, ...) GPGRT_ATTR_SENTINEL(0);
+char *gpgrt_absfnameconcat (const char *first, ...) GPGRT_ATTR_SENTINEL(0);
#ifdef __cplusplus
diff --git a/src/gpg-error.vers b/src/gpg-error.vers
index eef4cbc..594342b 100644
--- a/src/gpg-error.vers
+++ b/src/gpg-error.vers
@@ -199,6 +199,9 @@ GPG_ERROR_1.0 {
gpgrt_add_emergency_cleanup;
gpgrt_abort;
+ gpgrt_fnameconcat;
+ gpgrt_absfnameconcat;
+
local:
*;
};
diff --git a/src/gpgrt-int.h b/src/gpgrt-int.h
index 718b62c..97f0533 100644
--- a/src/gpgrt-int.h
+++ b/src/gpgrt-int.h
@@ -787,6 +787,17 @@ gpg_err_code_t _gpgrt_chdir (const char *name);
/* Return the current WD as a malloced string. */
char *_gpgrt_getcwd (void);
+/* Return the home directory of user NAME. */
+char *_gpgrt_getpwdir (const char *name);
+
+/* Expand and concat file name parts. */
+char *_gpgrt_vfnameconcat (int want_abs, const char *first_part,
+ va_list arg_ptr);
+char *_gpgrt_fnameconcat (const char *first_part,
+ ... ) GPGRT_ATTR_SENTINEL(0);
+char *_gpgrt_absfnameconcat (const char *first_part,
+ ... ) GPGRT_ATTR_SENTINEL(0);
+
/*
* Platform specific functions (Windows)
diff --git a/src/stringutils.c b/src/stringutils.c
new file mode 100644
index 0000000..d92398d
--- /dev/null
+++ b/src/stringutils.c
@@ -0,0 +1,224 @@
+/* stringutils.c - String helper functions.
+ * Copyright (C) 1997, 2014 Werner Koch
+ * Copyright (C) 2020 g10 Code GmbH
+ *
+ * This file is part of libgpg-error.
+ *
+ * libgpg-error is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * libgpg-error is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+#ifdef HAVE_STAT
+# include <sys/stat.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#include "gpgrt-int.h"
+
+
+/* Helper for _gpgrt_fnameconcat. The additional flag WANT_ABS tells
+ * whether an absolute file name is requested. */
+char *
+_gpgrt_vfnameconcat (int want_abs, const char *first_part, va_list arg_ptr)
+{
+ const char *argv[32];
+ int argc;
+ size_t n;
+ int skip = 1; /* Characters to skip from FIRST_PART. */
+ char *home_buffer = NULL;
+ char *name, *home, *p;
+
+ /* Put all args into an array becuase we need to scan them twice. */
+ 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)
+ {
+ _gpg_err_set_errno (EINVAL);
+ return NULL;
+ }
+ argc++;
+ }
+ n++;
+
+ home = NULL;
+ if (*first_part == '~')
+ {
+ if (first_part[1] == '/' || !first_part[1])
+ {
+ /* This is the "~/" or "~" case. */
+ home_buffer = _gpgrt_getenv ("HOME");
+ if (!home_buffer)
+ home_buffer = _gpgrt_getpwdir (NULL);
+ home = home_buffer;
+ if (home && *home)
+ n += strlen (home);
+ }
+ else
+ {
+ /* This is the "~username/" or "~username" case. */
+ char *user;
+
+ user = _gpgrt_strdup (first_part+1);
+ if (!user)
+ return NULL;
+
+ p = strchr (user, '/');
+ if (p)
+ *p = 0;
+ skip = 1 + strlen (user);
+
+ home = home_buffer = _gpgrt_getpwdir (user);
+ xfree (user);
+ if (home)
+ n += strlen (home);
+ else
+ skip = 1;
+ }
+ }
+
+ name = xtrymalloc (n);
+ if (!name)
+ {
+ _gpgrt_free (home_buffer);
+ return NULL;
+ }
+
+ if (home)
+ p = stpcpy (stpcpy (name, home), first_part + skip);
+ else
+ p = stpcpy (name, first_part);
+
+ xfree (home_buffer);
+ home_buffer = NULL;
+
+ for (argc=0; argv[argc]; argc++)
+ {
+ /* Avoid a leading double slash if the first part was "/". */
+ if (!argc && name[0] == '/' && !name[1])
+ p = stpcpy (p, argv[argc]);
+ else
+ p = stpcpy (stpcpy (p, "/"), argv[argc]);
+ }
+
+ if (want_abs)
+ {
+#ifdef HAVE_W32_SYSTEM
+ p = strchr (name, ':');
+ if (p)
+ p++;
+ else
+ p = name;
+#else
+ p = name;
+#endif
+ if (*p != '/'
+#ifdef HAVE_W32_SYSTEM
+ && *p != '\\'
+#endif
+ )
+ {
+ home = _gpgrt_getcwd ();
+ if (!home)
+ {
+ xfree (name);
+ return NULL;
+ }
+
+ n = strlen (home) + 1 + strlen (name) + 1;
+ home_buffer = xtrymalloc (n);
+ if (!home_buffer)
+ {
+ xfree (home);
+ xfree (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);
+ }
+
+ /* Avoid a leading double slash if the cwd is "/". */
+ if (home[0] == '/' && !home[1])
+ strcpy (stpcpy (p, "/"), name);
+ else
+ strcpy (stpcpy (stpcpy (p, home), "/"), name);
+
+ xfree (home);
+ xfree (name);
+ name = home_buffer;
+ /* Let's do a simple compression to catch the common case of
+ * a trailing "/.". */
+ n = strlen (name);
+ if (n > 2 && name[n-2] == '/' && name[n-1] == '.')
+ name[n-2] = 0;
+ }
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ for (p=name; *p; p++)
+ if (*p == '\\')
+ *p = '/';
+#endif
+ return name;
+}
+
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ * expansion is done for the first argument. The caller must release
+ * the result using gpgrt_free; on error ERRNO is set and NULL
+ * returned. */
+char *
+_gpgrt_fnameconcat (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = _gpgrt_vfnameconcat (0, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+
+/* Construct a filename from the NULL terminated list of parts. Tilde
+ * expansion is done for the first argument. The caller must release
+ * the result using gpgrt_free; on error ERRNO is set and NULL
+ * returned. This version returns an absolute filename. */
+char *
+_gpgrt_absfnameconcat (const char *first_part, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first_part);
+ result = _gpgrt_vfnameconcat (1, first_part, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
diff --git a/src/sysutils.c b/src/sysutils.c
index bc31d92..6bdd76f 100644
--- a/src/sysutils.c
+++ b/src/sysutils.c
@@ -32,6 +32,9 @@
#endif
#include <sys/types.h>
#include <fcntl.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
#include "gpgrt-int.h"
@@ -337,3 +340,39 @@ _gpgrt_getcwd (void)
#endif
}
}
+
+
+/* Get the standard home directory for user NAME. If NAME is NULL the
+ * directory for the current user is retruned. Caller must release
+ * the returned string. */
+char *
+_gpgrt_getpwdir (const char *name)
+{
+ char *result = NULL;
+#ifdef HAVE_PWD_H
+ struct passwd *pwd = NULL;
+
+ if (name)
+ {
+#ifdef HAVE_GETPWNAM
+ /* Fixme: We should use getpwnam_r if available. */
+ pwd = getpwnam (name);
+#endif
+ }
+ else
+ {
+#ifdef HAVE_GETPWUID
+ /* Fixme: We should use getpwuid_r if available. */
+ pwd = getpwuid (getuid());
+#endif
+ }
+ if (pwd)
+ {
+ result = _gpgrt_strdup (pwd->pw_dir);
+ }
+#else /*!HAVE_PWD_H*/
+ /* No support at all. */
+ (void)name;
+#endif /*HAVE_PWD_H*/
+ return result;
+}
diff --git a/src/visibility.c b/src/visibility.c
index d754032..5f88aad 100644
--- a/src/visibility.c
+++ b/src/visibility.c
@@ -1180,6 +1180,33 @@ gpgrt_cmp_version (const char *a, const char *b, int level)
+/* String utilities. */
+char *
+gpgrt_fnameconcat (const char *first, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first);
+ result = _gpgrt_vfnameconcat (0, first, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+char *
+gpgrt_absfnameconcat (const char *first, ... )
+{
+ va_list arg_ptr;
+ char *result;
+
+ va_start (arg_ptr, first);
+ result = _gpgrt_vfnameconcat (1, first, arg_ptr);
+ va_end (arg_ptr);
+ return result;
+}
+
+
+
/* For consistency reasons we use function wrappers also for Windows
* specific function despite that they are technically not needed. */
#ifdef HAVE_W32_SYSTEM
diff --git a/src/visibility.h b/src/visibility.h
index 28038d0..192f733 100644
--- a/src/visibility.h
+++ b/src/visibility.h
@@ -216,6 +216,10 @@ MARK_VISIBLE (gpgrt_set_usage_outfnc);
MARK_VISIBLE (gpgrt_cmp_version);
+MARK_VISIBLE (gpgrt_fnameconcat);
+MARK_VISIBLE (gpgrt_absfnameconcat);
+
+
#undef MARK_VISIBLE
#else /*!_GPGRT_INCL_BY_VISIBILITY_C*/