diff options
author | Mattias Andrée <maandree@kth.se> | 2021-04-06 12:19:09 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@kth.se> | 2021-04-06 12:19:09 +0200 |
commit | 8cbe78910a238c7432c6b428b742f123efb69623 (patch) | |
tree | fa4c0a71e7c3180223b6a381bafce8473edeedf3 | |
parent | update todo: no cache is needed (diff) | |
download | libcontacts-8cbe78910a238c7432c6b428b742f123efb69623.tar.gz libcontacts-8cbe78910a238c7432c6b428b742f123efb69623.tar.bz2 libcontacts-8cbe78910a238c7432c6b428b742f123efb69623.tar.xz |
libcontacts_save_contact: create directory if missing
Signed-off-by: Mattias Andrée <maandree@kth.se>
-rw-r--r-- | common.h | 1 | ||||
-rw-r--r-- | libcontacts_save_contact.c | 46 |
2 files changed, 45 insertions, 2 deletions
@@ -1,6 +1,7 @@ /* See LICENSE file for copyright and license details. */ #include "libcontacts.h" +#include <sys/stat.h> #include <alloca.h> #include <ctype.h> #include <dirent.h> 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) { |