From 8cbe78910a238c7432c6b428b742f123efb69623 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Tue, 6 Apr 2021 12:19:09 +0200 Subject: libcontacts_save_contact: create directory if missing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- common.h | 1 + libcontacts_save_contact.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/common.h b/common.h index 5bb22a1..3e2e4b4 100644 --- a/common.h +++ b/common.h @@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include "libcontacts.h" +#include #include #include #include diff --git a/libcontacts_save_contact.c b/libcontacts_save_contact.c index 2d9602b..89f8ebc 100644 --- a/libcontacts_save_contact.c +++ b/libcontacts_save_contact.c @@ -2,12 +2,38 @@ #include "common.h" +static int +makedirs(char *path) +{ + char *p, *last; + + last = strrchr(path, '/'); + if (!last) + return 0; + *last = '\0'; + + for (p = path; *p == '/'; p++); + + while (*p) { + for (; *p && *p != '/'; p++); + *p = '\0'; + if (mkdir(path, 0777) && errno != EEXIST) { + *last = *p = '/'; + return -1; + } + for (*p++ = '/'; *p == '/'; p++); + } + + *last = '/'; + return 0; +} + int libcontacts_save_contact(struct libcontacts_contact *contact, const struct passwd *user) { char *data = NULL, *path = NULL, *tmppath; int oflags = O_WRONLY | O_CREAT | O_TRUNC; - int fd = -1, saved_errno = errno; + int fd = -1, saved_errno = errno, dirs_created = 0; ssize_t r; size_t p, n, num = 0; char *basenam = NULL; @@ -52,8 +78,15 @@ libcontacts_save_contact(struct libcontacts_contact *contact, const struct passw stpcpy(stpcpy(tmppath, path), "~"); if (oflags & O_EXCL) { + open_excl_again: fd = open(path, oflags, 0666); if (fd < 0) { + if (errno == ENOENT && !dirs_created) { + if (makedirs(path)) + goto fail; + dirs_created = 1; + goto open_excl_again; + } if (errno != EEXIST) goto fail; if (!num++) { @@ -64,11 +97,20 @@ libcontacts_save_contact(struct libcontacts_contact *contact, const struct passw } close(fd); oflags ^= O_EXCL ^ O_TRUNC; + dirs_created = 1; } +open_again: fd = open(tmppath, oflags, 0666); - if (fd < 0) + if (fd < 0) { + if (errno == ENOENT && !dirs_created) { + if (makedirs(path)) + goto fail; + dirs_created = 1; + goto open_again; + } goto fail; + } n = strlen(data); for (p = 0; p < n; p += (size_t)r) { -- cgit v1.2.3-70-g09d2