aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias Andrée <maandree@kth.se>2021-04-06 12:19:09 +0200
committerMattias Andrée <maandree@kth.se>2021-04-06 12:19:09 +0200
commit8cbe78910a238c7432c6b428b742f123efb69623 (patch)
treefa4c0a71e7c3180223b6a381bafce8473edeedf3
parentupdate todo: no cache is needed (diff)
downloadlibcontacts-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.h1
-rw-r--r--libcontacts_save_contact.c46
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 <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) {