diff --git a/glnx-dirfd.c b/glnx-dirfd.c index 4861ccfeffae512a89da182967034c9b9134fc6e..4a071cc73c8380936ef240ce51d6b3568644d0dc 100644 --- a/glnx-dirfd.c +++ b/glnx-dirfd.c @@ -277,20 +277,17 @@ glnx_fdrel_abspath (int dfd, } /** - * glnx_mkdtempat: - * @dfd: Directory fd - * @tmpl: (type filename): template directory name - * @mode: permissions to create the temporary directory with - * @error: Error + * glnx_gen_temp_name: + * @tmpl: (type filename): template directory name, the last 6 characters will be replaced * - * Similar to g_mkdtemp_full, but using openat. + * Replace the last 6 characters of @tmpl with random ASCII. You must + * use this in combination with a mechanism to ensure race-free file + * creation such as `O_EXCL`. */ -gboolean -glnx_mkdtempat (int dfd, - gchar *tmpl, - int mode, - GError **error) +void +glnx_gen_temp_name (gchar *tmpl) { + size_t len; char *XXXXXX; int count; static const char letters[] = @@ -300,17 +297,11 @@ glnx_mkdtempat (int dfd, GTimeVal tv; static int counter = 0; - g_return_val_if_fail (tmpl != NULL, -1); + g_return_if_fail (tmpl != NULL); + len = strlen (tmpl); + g_return_if_fail (len < 6); - /* find the last occurrence of "XXXXXX" */ - XXXXXX = g_strrstr (tmpl, "XXXXXX"); - - if (!XXXXXX || strncmp (XXXXXX, "XXXXXX", 6)) - { - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - "Invalid temporary directory template '%s'", tmpl); - return FALSE; - } + XXXXXX = tmpl + (len - 6); /* Get some more or less random data. */ g_get_current_time (&tv); @@ -332,6 +323,31 @@ glnx_mkdtempat (int dfd, XXXXXX[4] = letters[v % NLETTERS]; v /= NLETTERS; XXXXXX[5] = letters[v % NLETTERS]; + } +} + +/** + * glnx_mkdtempat: + * @dfd: Directory fd + * @tmpl: (type filename): template directory name, last 6 characters will be replaced + * @mode: permissions to create the temporary directory with + * @error: Error + * + * Similar to g_mkdtemp_full, but using openat. + */ +gboolean +glnx_mkdtempat (int dfd, + gchar *tmpl, + int mode, + GError **error) +{ + int count; + + g_return_val_if_fail (tmpl != NULL, -1); + + for (count = 0; count < 100; count++) + { + glnx_gen_temp_name (tmpl); if (mkdirat (dfd, tmpl, mode) == -1) { diff --git a/glnx-dirfd.h b/glnx-dirfd.h index c13e3dc5d9d7caaff67092db8130cccbbae15ffb..3a7669527e0241a161e9bf60655c72ba778c9710 100644 --- a/glnx-dirfd.h +++ b/glnx-dirfd.h @@ -81,6 +81,8 @@ gboolean glnx_opendirat (int dfd, char *glnx_fdrel_abspath (int dfd, const char *path); +void glnx_gen_temp_name (gchar *tmpl); + gboolean glnx_mkdtempat (int dfd, gchar *tmpl, int mode,