skip to content
==> src/fleet_store.c <==
1/* peer.rs Store. */
2#include "mesh/fleet_store.h"
3#include "mesh/mt.h"
4
5#include <errno.h>
6#include <fcntl.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12static char *read_all(const char *path, int *e) {
13    FILE *f = fopen(path, "rb");
14    if (!f) {
15        *e = errno;
16        return NULL;
17    }
18    mt_buf b = {0};
19    char chunk[4096];
20    size_t n;
21    while ((n = fread(chunk, 1, sizeof chunk, f)) > 0) mt_putn(&b, chunk, n);
22    fclose(f);
23    return mt_take(&b);
24}
25
26bool mfs_open(const char *path, uint32_t n, mfs_store *out, mfp_persist *p, char **err) {
27    int e = 0;
28    char *text = read_all(path, &e);
29    mfp_persist got = {0};
30    if (text) {
31        char *why = NULL;
32        bool ok = mfp_decode(text, n, &got, &why);
33        free(text);
34        if (!ok) {
35            *err = mt_fmt("--fleet-state %s: %s", path, why);
36            free(why);
37            return false;
38        }
39    } else if (e != ENOENT) {
40        *err = mt_fmt("--fleet-state %s: %s", path, strerror(e));
41        return false;
42    }
43    mfs_store s = {mt_strdup(path), n};
44    if (!mfs_write(&s, &got, err)) {
45        mfs_close(&s);
46        mfp_free(&got);
47        return false;
48    }
49    *out = s;
50    *p = got;
51    return true;
52}
53
54bool mfs_write(const mfs_store *s, const mfp_persist *p, char **err) {
55    /* path.with_extension("tmp") */
56    const char *slash = strrchr(s->path, '/'), *dot = strrchr(s->path, '.');
57    char *tmp = dot && (!slash || dot > slash + 1) ? mt_fmt("%.*s.tmp", (int)(dot - s->path), s->path) : mt_fmt("%s.tmp", s->path);
58    char *text = mfp_encode(p, s->n);
59    size_t len = strlen(text);
60    bool ok = false;
61    int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC, 0644);
62    if (fd < 0) goto fail;
63    for (size_t at = 0; at < len;) {
64        ssize_t w = write(fd, text + at, len - at);
65        if (w < 0 && errno == EINTR) continue;
66        if (w <= 0) {
67            close(fd);
68            goto fail;
69        }
70        at += (size_t)w;
71    }
72    if (fsync(fd) != 0) {
73        close(fd);
74        goto fail;
75    }
76    close(fd);
77    if (rename(tmp, s->path) != 0) goto fail;
78    if (slash && slash != s->path) {
79        char *dir = mt_strndup(s->path, (size_t)(slash - s->path));
80        int dfd = open(dir, O_RDONLY);
81        free(dir);
82        if (dfd < 0) goto fail;
83        int r = fsync(dfd);
84        close(dfd);
85        if (r != 0) goto fail;
86    }
87    ok = true;
88    goto done;
89fail:
90    *err = mt_fmt("--fleet-state %s: %s", s->path, strerror(errno));
91done:
92    free(tmp);
93    free(text);
94    return ok;
95}
96
97void mfs_close(mfs_store *s) {
98    free(s->path);
99    *s = (mfs_store){0};
100}