==> 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}