summaryrefslogtreecommitdiffstats
path: root/src/update.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/update.c')
-rw-r--r--src/update.c207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/update.c b/src/update.c
new file mode 100644
index 0000000..2104217
--- /dev/null
+++ b/src/update.c
@@ -0,0 +1,207 @@
+#include <dirent.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <time.h>
+
+#include "update.h"
+#include "dbstruct.h"
+#include "util.h"
+#include "dbutil.h"
+#include "md5util.h"
+
+static int dbput(DB* db, const void *k, int klen, const void*d, int dlen, int f) {
+ DBT key, data;
+ int ret;
+
+ memset(&key, 0, sizeof(key));
+ key.data = (void*) k;
+ key.size = klen;
+
+ memset(&data, 0, sizeof(data));
+ data.data = (void*) d;
+ data.size = dlen;
+
+ if ((ret = db->put(db, NULL, &key, &data, f)) != 0) {
+ if (ret != DB_KEYEXIST) {
+ db->err(db, ret, "db::put()");
+ return -1;
+ }
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static int write_entry(struct syrep_db_context *c, const struct syrep_name *name, const struct syrep_md *md, const struct syrep_meta *meta) {
+ struct syrep_id id;
+ int f;
+
+ assert(c && c->db_id_meta && c->db_md_name && c->db_name_md && c->db_md_lastname && c->db_name_lastmd && name && md && meta);
+
+ /*** Update id_meta ***/
+ memset(&id, 0, sizeof(id));
+ memcpy(&id.name, name, sizeof(struct syrep_name));
+ memcpy(&id.md, md, sizeof(struct syrep_md));
+
+ if (dbput(c->db_id_meta, &id, sizeof(struct syrep_id), meta, sizeof(struct syrep_meta), 0) < 0)
+ return -1;
+
+ /*** Update md_name ***/
+ if (dbput(c->db_md_name, md, sizeof(struct syrep_md), name, sizeof(struct syrep_name), DB_NODUPDATA) < 0)
+ return -1;
+
+ /*** Update name_md ***/
+ if (dbput(c->db_name_md, name, sizeof(struct syrep_name), md, sizeof(struct syrep_md), DB_NODUPDATA) < 0)
+ return -1;
+
+ /*** Update md_lastname ***/
+ if (dbput(c->db_md_lastname, md, sizeof(struct syrep_md), name, sizeof(struct syrep_name), 0) < 0)
+ return -1;
+
+ /*** Update name_lastmd ***/
+ if ((f = dbput(c->db_name_lastmd, name, sizeof(struct syrep_name), md, sizeof(struct syrep_md), 0)) < 0)
+ return -1;
+
+ //fprintf(stderr, "Insert: %s %i\n", name->path, f);
+
+ c->modified = 1;
+ return 0;
+}
+
+static int handle_file(struct syrep_db_context *c, uint32_t version, const char *path, const struct syrep_md *md) {
+ int r;
+ struct syrep_meta meta;
+ struct syrep_name name;
+
+ memset(&name, 0, sizeof(name));
+ strncpy(name.path, path, PATH_MAX);
+
+ memset(&meta, 0, sizeof(meta));
+
+ if ((r = get_meta_by_name_md(c, &name, md, &meta)) < 0)
+ return -1;
+
+ if (r) { /* File is alread known */
+
+ if (meta.last_seen != c->version) { /* File was deleted preiously */
+ if (args.verbose_flag)
+ fprintf(stderr, "%s: File reappeared\n", path);
+ meta.first_seen = meta.last_seen = version;
+ } else { /* File is not new */
+ if (args.verbose_flag)
+ fprintf(stderr, "%s: File still available\n", path);
+ meta.last_seen = version;
+ }
+
+ } else { /* File is new */
+ if (args.verbose_flag)
+ fprintf(stderr, "%s: File is new\n", path);
+ meta.first_seen = meta.last_seen = version;
+ }
+
+ return write_entry(c, &name, md, &meta);
+}
+
+static int iterate_dir(struct syrep_db_context *c, struct syrep_md_cache *cache, uint32_t version, const char *root) {
+ DIR *dir;
+ struct dirent *de;
+ char p[PATH_MAX];
+
+ if (!(dir = opendir(root)))
+ return -1;
+
+ while ((de = readdir(dir))) {
+ struct syrep_md md;
+ struct stat st;
+
+ if (de->d_name[0] == '.')
+ continue;
+
+ if (!strncmp(de->d_name, ".syrep", 6))
+ continue;
+
+ if (args.progress_flag)
+ rotdash();
+
+ snprintf(p, sizeof(p), "%s/%s", root, de->d_name);
+
+ normalize_path(p);
+
+ if (stat(p, &st) < 0) {
+ fprintf(stderr, "stat(%s) failed: %s\n", p, strerror(errno));
+ continue;
+ }
+
+ if (S_ISDIR(st.st_mode)) {
+ if (iterate_dir(c, cache, version, p) < 0)
+ fprintf(stderr, "iterate_dir(%s) failed: %s\n", p, strerror(errno));
+ } else if (S_ISREG(st.st_mode)) {
+ if (md_cache_get(cache, p, md.digest) < 0)
+ continue;
+
+ if ((handle_file(c, version, p, &md)) < 0) {
+ fprintf(stderr, "handle_file(%s) failed.\n", p);
+ return -1;
+ }
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+static int new_version(struct syrep_db_context *c, uint32_t v, uint32_t t) {
+ DBT key, data;
+ struct syrep_version version;
+ struct syrep_timestamp timestamp;
+ int ret;
+
+ assert(c && c->db_version_timestamp);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ memset(&version, 0, sizeof(version));
+ memset(&timestamp, 0, sizeof(timestamp));
+
+ version.v = v;
+ key.data = &version;
+ key.size = sizeof(version);
+
+ timestamp.t = t;
+ data.data = &timestamp;
+ data.size = sizeof(timestamp);
+
+ if ((ret = c->db_version_timestamp->put(c->db_version_timestamp, NULL, &key, &data, 0))) {
+ c->db_version_timestamp->err(c->db_version_timestamp, ret, "version_timestamp::get");
+ return -1;
+ }
+
+ c->timestamp = t;
+ c->version = v;
+
+ return 0;
+}
+
+int update(struct syrep_db_context *c, struct syrep_md_cache *cache) {
+ uint32_t now, version;
+
+ assert(c);
+
+ now = (uint32_t) time(NULL);
+ version = c->version+1;
+
+ if (iterate_dir(c, cache, version, ".") < 0)
+ return -1;
+
+ if (new_version(c, version, now) < 0)
+ return -1;
+
+ if (args.verbose_flag)
+ fprintf(stderr, "Wrote version %u.\n", c->version);
+
+ return 0;
+}