aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--activitypub.c6
-rw-r--r--data.c69
-rw-r--r--httpd.c2
-rw-r--r--main.c6
-rw-r--r--snac.h3
5 files changed, 86 insertions, 0 deletions
diff --git a/activitypub.c b/activitypub.c
index d699fee..5fb60ba 100644
--- a/activitypub.c
+++ b/activitypub.c
@@ -3377,6 +3377,12 @@ void process_queue_item(xs_dict *q_item)
rss_poll_hashtags();
}
else
+ if (strcmp(type, "fsck") == 0) {
+ srv_log(xs_fmt("started deferred data integrity check"));
+ data_fsck();
+ srv_log(xs_fmt("finished deferred data integrity check"));
+ }
+ else
srv_log(xs_fmt("unexpected q_item type '%s'", type));
}
diff --git a/data.c b/data.c
index b36e31e..1533305 100644
--- a/data.c
+++ b/data.c
@@ -3605,6 +3605,17 @@ void enqueue_collect_outbox(snac *user, const char *actor_id)
}
+void enqueue_fsck(void)
+/* enqueues an fsck */
+{
+ xs *qmsg = _new_qmsg("fsck", "", 0);
+ const char *ntid = xs_dict_get(qmsg, "ntid");
+ xs *fn = xs_fmt("%s/queue/%s.json", srv_basedir, ntid);
+
+ qmsg = _enqueue_put(fn, qmsg);
+}
+
+
int was_question_voted(snac *user, const char *id)
/* returns true if the user voted in this poll */
{
@@ -4362,3 +4373,61 @@ const char *lang_str(const char *str, const snac *user)
return n_str;
}
+
+
+/** integrity checks **/
+
+void data_fsck(void)
+{
+ xs *list = user_list();
+ const char *uid;
+
+ xs_list_foreach(list, uid) {
+ snac user;
+
+ if (!user_open(&user, uid))
+ continue;
+
+ {
+ /* iterate all private posts and check that non-public posts
+ from this user are also linked into the public directory,
+ to avoid the don't-fucking-delete-my-own-private-posts purge bug */
+
+ xs *priv_spec = xs_fmt("%s/private/""*.json", user.basedir);
+ xs *posts = xs_glob(priv_spec, 0, 0);
+ const char *priv_fn;
+
+ xs_list_foreach(posts, priv_fn) {
+ xs *pub_fn = xs_replace(priv_fn, "/private/", "/public/");
+
+ /* already there? look no more */
+ if (mtime(pub_fn))
+ continue;
+
+ /* read the post */
+ FILE *f;
+ if ((f = fopen(priv_fn, "r")) == NULL)
+ continue;
+
+ xs *post = xs_json_load(f);
+ fclose(f);
+
+ if (!xs_is_dict(post))
+ continue;
+
+ const char *attr_to = get_atto(post);
+
+ if (!xs_is_string(attr_to) || strcmp(attr_to, user.actor) != 0) {
+ /* not from this user */
+ continue;
+ }
+
+ /* link */
+ snac_debug(&user, 1, xs_fmt("fsck: fixed missing link %s", xs_dict_get(post, "id")));
+ link(priv_fn, pub_fn);
+ }
+ }
+
+ user_free(&user);
+ }
+}
diff --git a/httpd.c b/httpd.c
index 9707f9c..50f56f2 100644
--- a/httpd.c
+++ b/httpd.c
@@ -805,6 +805,8 @@ static void *background_thread(void *arg)
srv_log(xs_fmt("background thread started"));
+ enqueue_fsck();
+
while (p_state->srv_running) {
int cnt = 0;
diff --git a/main.c b/main.c
index f767355..19cfe1a 100644
--- a/main.c
+++ b/main.c
@@ -34,6 +34,7 @@ int usage(const char *cmd)
"httpd {basedir} Starts the HTTPD daemon\n"
"purge {basedir} Purges old data\n"
"state {basedir} Prints server state\n"
+ "fsck {basedir} Performs a non-destructive data integrity check\n"
"webfinger {basedir} {account} Queries about an account (@user@host or actor url)\n"
"queue {basedir} {uid} Processes a user queue\n"
"follow {basedir} {uid} {actor} Follows an actor\n"
@@ -200,6 +201,11 @@ int main(int argc, char *argv[])
return 0;
}
+ if (strcmp(cmd, "fsck") == 0) { /** **/
+ data_fsck();
+ return 0;
+ }
+
if ((user = GET_ARGV()) == NULL)
return usage(cmd);
diff --git a/snac.h b/snac.h
index e4f5262..e344f46 100644
--- a/snac.h
+++ b/snac.h
@@ -299,6 +299,7 @@ void enqueue_webmention(const xs_dict *msg);
void enqueue_notify_webhook(snac *user, const xs_dict *noti, int retries);
void enqueue_collect_replies(snac *user, const char *post);
void enqueue_collect_outbox(snac *user, const char *actor_id);
+void enqueue_fsck(void);
int was_question_voted(snac *user, const char *id);
@@ -477,3 +478,5 @@ xs_str *rss_from_timeline(snac *user, const xs_list *timeline,
const char *title, const char *link, const char *desc);
void rss_to_timeline(snac *user, const char *url);
void rss_poll_hashtags(void);
+
+void data_fsck(void);