aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2020-10-21 14:59:38 +0000
committerWerner Koch <[email protected]>2020-10-23 09:24:09 +0000
commit5f8123df7856b724a062177026fe669ae49be263 (patch)
treeee9dae116e3d885d3c57c465849e52013a6a2d51
parentw32: Make gnupg_remove and gnupg_rename_file Unicode aware (diff)
downloadgnupg-5f8123df7856b724a062177026fe669ae49be263.tar.gz
gnupg-5f8123df7856b724a062177026fe669ae49be263.zip
common: New functions gnupg_opendir et al.
* common/sysutils.h (struct gnupg_dirent_s): New. * common/sysutils.c: Include dirent.h. (struct gnupg_dir_s): New. (gnupg_opendir, gnupg_readdir, gnupg_closedir): New. Change all callers of opendir, readdir, and closedir to use these functions. -- GnuPG-bug-id: 5098 Backported-from-master: 7e22e08e2ab09cd3c2317f5e80e8ee47d46eff4b
-rw-r--r--agent/command.c11
-rw-r--r--common/sysutils.c162
-rw-r--r--common/sysutils.h16
-rw-r--r--dirmngr/certcache.c10
-rw-r--r--dirmngr/crlcache.c22
-rw-r--r--dirmngr/dirmngr.c2
-rw-r--r--tools/gpg-wks-server.c22
-rw-r--r--tools/gpgtar-create.c2
8 files changed, 210 insertions, 37 deletions
diff --git a/agent/command.c b/agent/command.c
index 9e3483e8c..2cac9cc43 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1260,7 +1260,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx);
int err;
unsigned char grip[20];
- DIR *dir = NULL;
+ gnupg_dir_t dir = NULL;
int list_mode;
int opt_data, opt_ssh_fpr, opt_with_ssh;
ssh_control_file_t cf = NULL;
@@ -1316,7 +1316,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
else if (list_mode)
{
char *dirname;
- struct dirent *dir_entry;
+ gnupg_dirent_t dir_entry;
dirname = make_filename_try (gnupg_homedir (),
GNUPG_PRIVATE_KEYS_DIR, NULL);
@@ -1325,7 +1325,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
err = gpg_error_from_syserror ();
goto leave;
}
- dir = opendir (dirname);
+ dir = gnupg_opendir (dirname);
if (!dir)
{
err = gpg_error_from_syserror ();
@@ -1334,7 +1334,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
}
xfree (dirname);
- while ( (dir_entry = readdir (dir)) )
+ while ( (dir_entry = gnupg_readdir (dir)) )
{
if (strlen (dir_entry->d_name) != 44
|| strcmp (dir_entry->d_name + 40, ".key"))
@@ -1385,8 +1385,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
leave:
ssh_close_control_file (cf);
- if (dir)
- closedir (dir);
+ gnupg_closedir (dir);
if (err && gpg_err_code (err) != GPG_ERR_NOT_FOUND)
leave_cmd (ctx, err);
return err;
diff --git a/common/sysutils.c b/common/sysutils.c
index 422a783e5..acfea7db6 100644
--- a/common/sysutils.c
+++ b/common/sysutils.c
@@ -73,6 +73,7 @@
# include <npth.h>
#endif
#include <fcntl.h>
+#include <dirent.h>
#include <assuan.h>
@@ -83,6 +84,22 @@
#define tohex(n) ((n) < 10 ? ((n) + '0') : (((n) - 10) + 'A'))
+
+/* The object used with our opendir functions. We need to define our
+ * own so that we can properly handle Unicode on Windows. */
+struct gnupg_dir_s
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir; /* The system's DIR pointer. */
+#else
+ DIR *dir; /* The system's DIR pointer. */
+#endif
+ struct gnupg_dirent_s dirent; /* The current dirent. */
+ size_t namesize; /* If not 0 the allocated size of dirent.d_name. */
+ char name[256]; /* Only used if NAMESIZE is 0. */
+};
+
+
/* Flag to tell whether special file names are enabled. See gpg.c for
* an explanation of these file names. */
static int allow_special_filenames;
@@ -1205,6 +1222,151 @@ gnupg_open (const char *name, int flags, unsigned int mode)
}
+/* A wrapper around opendir to handle Unicode file names under
+ * Windows. This assumes the mingw toolchain. */
+gnupg_dir_t
+gnupg_opendir (const char *name)
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir;
+ wchar_t *wname;
+#else
+ DIR *dir;
+#endif
+ gnupg_dir_t gdir;
+
+#ifdef HAVE_W32_SYSTEM
+ /* Note: See gpgtar-create for an alternative implementation which
+ * could be used here to avoid a mingw dependency. */
+ wname = utf8_to_wchar (name);
+ if (!wname)
+ return NULL;
+ dir = _wopendir (wname);
+ xfree (wname);
+#else
+ dir = opendir (name);
+#endif
+
+ if (!dir)
+ return NULL;
+
+ gdir = xtrymalloc (sizeof *gdir);
+ if (!gdir)
+ {
+ int save_errno = errno;
+#ifdef HAVE_W32_SYSTEM
+ _wclosedir (dir);
+#else
+ closedir (dir);
+#endif
+ gpg_err_set_errno (save_errno);
+ return NULL;
+ }
+ gdir->dir = dir;
+ gdir->namesize = 0;
+ gdir->dirent.d_name = gdir->name;
+
+ return gdir;
+}
+
+
+gnupg_dirent_t
+gnupg_readdir (gnupg_dir_t gdir)
+{
+#ifdef HAVE_W32_SYSTEM
+ char *namebuffer = NULL;
+ struct _wdirent *de;
+#else
+ struct dirent *de;
+#endif
+ size_t n;
+ gnupg_dirent_t gde;
+ const char *name;
+
+ if (!gdir)
+ {
+ gpg_err_set_errno (EINVAL);
+ return 0;
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ de = _wreaddir (gdir->dir);
+ if (!de)
+ return NULL;
+ namebuffer = wchar_to_utf8 (de->d_name);
+ if (!namebuffer)
+ return NULL;
+ name = namebuffer;
+#else
+ de = readdir (gdir->dir);
+ if (!de)
+ return NULL;
+ name = de->d_name;
+#endif
+
+ gde = &gdir->dirent;
+ n = strlen (name);
+ if (gdir->namesize)
+ {
+ /* Use allocated buffer. */
+ if (n+1 >= gdir->namesize || !gde->d_name)
+ {
+ gdir->namesize = n + 256;
+ xfree (gde->d_name);
+ gde->d_name = xtrymalloc (gdir->namesize);
+ if (!gde->d_name)
+ return NULL; /* ERRNO is already set. */
+ }
+ strcpy (gde->d_name, name);
+ }
+ else if (n+1 >= sizeof (gdir->name))
+ {
+ /* Switch to allocated buffer. */
+ gdir->namesize = n + 256;
+ gde->d_name = xtrymalloc (gdir->namesize);
+ if (!gde->d_name)
+ return NULL; /* ERRNO is already set. */
+ strcpy (gde->d_name, name);
+ }
+ else
+ {
+ /* Use static buffer. */
+ gde->d_name = gdir->name;
+ strcpy (gde->d_name, name);
+ }
+
+#ifdef HAVE_W32_SYSTEM
+ xfree (namebuffer);
+#endif
+
+ return gde;
+}
+
+
+int
+gnupg_closedir (gnupg_dir_t gdir)
+{
+#ifdef HAVE_W32_SYSTEM
+ _WDIR *dir;
+#else
+ DIR *dir;
+#endif
+
+ if (!gdir)
+ return 0;
+ dir = gdir->dir;
+ if (gdir->namesize)
+ xfree (gdir->dirent.d_name);
+ xfree (gdir);
+
+#ifdef HAVE_W32_SYSTEM
+ return _wclosedir (dir);
+#else
+ return closedir (dir);
+#endif
+}
+
+
#ifdef HAVE_W32CE_SYSTEM
/* There is a isatty function declaration in cegcc but it does not
diff --git a/common/sysutils.h b/common/sysutils.h
index 1862926ef..63c259b0d 100644
--- a/common/sysutils.h
+++ b/common/sysutils.h
@@ -50,6 +50,19 @@ typedef int gnupg_fd_t;
# include <sys/stat.h>
#endif
+struct gnupg_dir_s;
+typedef struct gnupg_dir_s *gnupg_dir_t;
+struct gnupg_dirent_s
+{
+ /* We don't have a d_ino because that can't be used on Windows
+ * anyway. D_NAME is a pointer into the gnupg_dir_s which has a
+ * static buffer or allocates sufficient space as needed. This is
+ * only valid after gnupg_readdir. */
+ char *d_name;
+};
+typedef struct gnupg_dirent_s *gnupg_dirent_t;
+
+
void trap_unaligned (void);
int disable_core_dumps (void);
int enable_core_dumps (void);
@@ -80,6 +93,9 @@ gpg_err_code_t gnupg_access (const char *name, int mode);
int gnupg_stat (const char *name, struct stat *statbuf);
#endif /*HAVE_STAT*/
int gnupg_open (const char *name, int flags, unsigned int mode);
+gnupg_dir_t gnupg_opendir (const char *name);
+gnupg_dirent_t gnupg_readdir (gnupg_dir_t gdir);
+int gnupg_closedir (gnupg_dir_t gdir);
char *gnupg_get_socket_name (int fd);
int gnupg_fd_valid (int fd);
diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c
index 04da510a0..9ca6069a2 100644
--- a/dirmngr/certcache.c
+++ b/dirmngr/certcache.c
@@ -364,8 +364,8 @@ static gpg_error_t
load_certs_from_dir (const char *dirname, unsigned int trustclass)
{
gpg_error_t err;
- DIR *dir;
- struct dirent *ep;
+ gnupg_dir_t dir;
+ gnupg_dirent_t ep;
char *p;
size_t n;
estream_t fp;
@@ -373,13 +373,13 @@ load_certs_from_dir (const char *dirname, unsigned int trustclass)
ksba_cert_t cert;
char *fname = NULL;
- dir = opendir (dirname);
+ dir = gnupg_opendir (dirname);
if (!dir)
{
return 0; /* We do not consider this a severe error. */
}
- while ( (ep=readdir (dir)) )
+ while ( (ep = gnupg_readdir (dir)) )
{
p = ep->d_name;
if (*p == '.' || !*p)
@@ -447,7 +447,7 @@ load_certs_from_dir (const char *dirname, unsigned int trustclass)
}
xfree (fname);
- closedir (dir);
+ gnupg_closedir (dir);
return 0;
}
diff --git a/dirmngr/crlcache.c b/dirmngr/crlcache.c
index 6468ce38f..eee4b7229 100644
--- a/dirmngr/crlcache.c
+++ b/dirmngr/crlcache.c
@@ -101,10 +101,6 @@
#ifndef HAVE_W32_SYSTEM
#include <sys/utsname.h>
#endif
-#ifdef MKDIR_TAKES_ONE_ARG
-#undef mkdir
-#define mkdir(a,b) mkdir(a)
-#endif
#include "dirmngr.h"
#include "validate.h"
@@ -206,15 +202,15 @@ get_current_cache (void)
static int
create_directory_if_needed (const char *name)
{
- DIR *dir;
+ gnupg_dir_t dir;
char *fname;
fname = make_filename (opt.homedir_cache, name, NULL);
- dir = opendir (fname);
+ dir = gnupg_opendir (fname);
if (!dir)
{
log_info (_("creating directory '%s'\n"), fname);
- if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR) )
+ if (gnupg_mkdir (fname, "-rwx"))
{
int save_errno = errno;
log_error (_("error creating directory '%s': %s\n"),
@@ -225,7 +221,7 @@ create_directory_if_needed (const char *name)
}
}
else
- closedir (dir);
+ gnupg_closedir (dir);
xfree (fname);
return 0;
}
@@ -237,8 +233,8 @@ static int
cleanup_cache_dir (int force)
{
char *dname = make_filename (opt.homedir_cache, DBDIR_D, NULL);
- DIR *dir;
- struct dirent *de;
+ gnupg_dir_t dir;
+ gnupg_dirent_t de;
int problem = 0;
if (!force)
@@ -251,7 +247,7 @@ cleanup_cache_dir (int force)
}
}
- dir = opendir (dname);
+ dir = gnupg_opendir (dname);
if (!dir)
{
log_error (_("error reading directory '%s': %s\n"),
@@ -260,7 +256,7 @@ cleanup_cache_dir (int force)
return -1;
}
- while ((de = readdir (dir)))
+ while ((de = gnupg_readdir (dir)))
{
if (strcmp (de->d_name, "." ) && strcmp (de->d_name, ".."))
{
@@ -289,7 +285,7 @@ cleanup_cache_dir (int force)
}
}
xfree (dname);
- closedir (dir);
+ gnupg_closedir (dir);
return problem;
}
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 4a29bf8ad..3500e7eea 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -1277,7 +1277,7 @@ main (int argc, char **argv)
{
log_error (_("error binding socket to '%s': %s\n"),
serv_addr.sun_path,
- gpg_strerror (gpg_error_from_errno (errno)));
+ gpg_strerror (gpg_error_from_syserror ()));
assuan_sock_close (fd);
dirmngr_exit (1);
}
diff --git a/tools/gpg-wks-server.c b/tools/gpg-wks-server.c
index 6e5e9eb82..addafa27d 100644
--- a/tools/gpg-wks-server.c
+++ b/tools/gpg-wks-server.c
@@ -1608,22 +1608,22 @@ static gpg_error_t
get_domain_list (strlist_t *r_list)
{
gpg_error_t err;
- DIR *dir = NULL;
+ gnupg_dir_t dir = NULL;
char *fname = NULL;
- struct dirent *dentry;
+ gnupg_dirent_t dentry;
struct stat sb;
strlist_t list = NULL;
*r_list = NULL;
- dir = opendir (opt.directory);
+ dir = gnupg_opendir (opt.directory);
if (!dir)
{
err = gpg_error_from_syserror ();
goto leave;
}
- while ((dentry = readdir (dir)))
+ while ((dentry = gnupg_readdir (dir)))
{
if (*dentry->d_name == '.')
continue;
@@ -1663,8 +1663,7 @@ get_domain_list (strlist_t *r_list)
leave:
free_strlist (list);
- if (dir)
- closedir (dir);
+ gnupg_closedir (dir);
xfree (fname);
return err;
}
@@ -1677,8 +1676,8 @@ expire_one_domain (const char *top_dirname, const char *domain)
gpg_error_t err;
char *dirname;
char *fname = NULL;
- DIR *dir = NULL;
- struct dirent *dentry;
+ gnupg_dir_t dir = NULL;
+ gnupg_dirent_t dentry;
struct stat sb;
time_t now = gnupg_get_time ();
@@ -1691,7 +1690,7 @@ expire_one_domain (const char *top_dirname, const char *domain)
goto leave;
}
- dir = opendir (dirname);
+ dir = gnupg_opendir (dirname);
if (!dir)
{
err = gpg_error_from_syserror ();
@@ -1700,7 +1699,7 @@ expire_one_domain (const char *top_dirname, const char *domain)
goto leave;
}
- while ((dentry = readdir (dir)))
+ while ((dentry = gnupg_readdir (dir)))
{
if (*dentry->d_name == '.')
continue;
@@ -1749,8 +1748,7 @@ expire_one_domain (const char *top_dirname, const char *domain)
err = 0;
leave:
- if (dir)
- closedir (dir);
+ gnupg_closedir (dir);
xfree (dirname);
xfree (fname);
return err;
diff --git a/tools/gpgtar-create.c b/tools/gpgtar-create.c
index 17c24c3d5..c196b96f6 100644
--- a/tools/gpgtar-create.c
+++ b/tools/gpgtar-create.c
@@ -301,6 +301,8 @@ scan_directory (const char *dname, scanctrl_t scanctrl)
gpg_error_t err = 0;
#ifdef HAVE_W32_SYSTEM
+ /* Note that we introduced gnupg_opendir only after we had deployed
+ * this code and thus we don't change it for now. */
WIN32_FIND_DATAW fi;
HANDLE hd = INVALID_HANDLE_VALUE;
char *p;