From a952692561d8b1c59d4a384812b52d7225953bb3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Jul 2004 16:04:48 +0000 Subject: add support for --forget git-svn-id: file:///home/lennart/svn/public/syrep/trunk@58 07ea20a6-d2c5-0310-9e02-9ef735347d72 --- doc/todo.txt | 2 +- src/Makefile.am | 3 +- src/dbstruct.h | 1 + src/dbutil.c | 7 --- src/forget.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/forget.h | 28 +++++++++ src/history.c | 2 +- src/package.c | 2 - src/syrep.c | 151 ++++++++++++++++++++++++++++++++------------ src/syrep.ggo | 3 + src/update.c | 4 +- src/update.h | 4 ++ 12 files changed, 344 insertions(+), 55 deletions(-) create mode 100644 src/forget.c create mode 100644 src/forget.h diff --git a/doc/todo.txt b/doc/todo.txt index 762843c..30ab367 100644 --- a/doc/todo.txt +++ b/doc/todo.txt @@ -31,7 +31,7 @@ post-0.1: - some more asserts - PATH_MAX or PATH_MAX+1? DONE - add --always-copy DONE -- add --forget +- add --forget DONE - valgrind $Id$ diff --git a/src/Makefile.am b/src/Makefile.am index de07fbc..d829809 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,7 +38,8 @@ syrep_SOURCES = cache.c cache.h \ cleanup.c cleanup.h \ cmdline.c cmdline.h \ svn-revision.h \ - dbstruct.h + dbstruct.h \ + forget.c forget.h EXTRA_DIST = syrep.ggo MAINTAINERCLEANFILES = diff --git a/src/dbstruct.h b/src/dbstruct.h index 842e33d..d0a7a85 100644 --- a/src/dbstruct.h +++ b/src/dbstruct.h @@ -68,6 +68,7 @@ struct syrep_name { * syrep_id :: syrep_meta => id_meta * syrep_md :: syrep_nrecno => md_nrecno (DUP) * syrep_nrecno :: syrep_md => nrecno_md (DUP) + * * syrep_nrecno :: syrep_md => nrecno_lastmd * syrep_md :: syrep_nrecno => md_lastnrecno * diff --git a/src/dbutil.c b/src/dbutil.c index cfa3150..09c092d 100644 --- a/src/dbutil.c +++ b/src/dbutil.c @@ -268,8 +268,6 @@ int get_nrecno_by_name(struct syrep_db_context *c, const struct syrep_name *rnam struct syrep_nrecno nrecno; struct syrep_name name; -/* struct syrep_nhash *foo1; */ -/* struct syrep_nrecno *foo2; */ int f; if (ret) { @@ -289,11 +287,6 @@ int get_nrecno_by_name(struct syrep_db_context *c, const struct syrep_name *rnam goto finish; } -/* foo1 = key.data; */ -/* foo2 = data.data; */ - -/* fprintf(stderr, "cursor: %u ?= %u, %u\n", nhash.hash, foo1->hash, foo2->recno); */ - memcpy(&nrecno, data.data, sizeof(nrecno)); if ((f = get_name_by_nrecno(c, &nrecno, &name)) < 0) diff --git a/src/forget.c b/src/forget.c new file mode 100644 index 0000000..befcf3f --- /dev/null +++ b/src/forget.c @@ -0,0 +1,192 @@ +/* $Id$ */ + +/*** + This file is part of syrep. + + syrep is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + syrep is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with syrep; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +***/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include "forget.h" +#include "dbstruct.h" +#include "util.h" +#include "dbutil.h" +#include "update.h" + +static int copy_entries(struct syrep_db_context *c, struct syrep_db_context *target, uint32_t limit) { + int ret, r = -1; + DBT key, data; + DBC *cursor = NULL; + unsigned n = 0, t = 0; + assert(c); + + if ((ret = c->db_id_meta->cursor(c->db_id_meta, NULL, &cursor, 0)) != 0) { + c->db_id_meta->err(c->db_id_meta, ret, "id_meta"); + goto finish; + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + while ((ret = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) { + struct syrep_id *id = (struct syrep_id*) key.data; + struct syrep_meta *meta = (struct syrep_meta*) data.data; + struct syrep_name name; + uint32_t ts; + + if (interrupted) { + fprintf(stderr, "Canceled.\n"); + goto finish; + } + + rotdash(); + t++; + + if ((ts = get_version_timestamp(c, meta->last_seen)) == (uint32_t) -1) + goto finish; + + if (ts < limit) + continue; + + n++; + + /* copy it */ + if (get_name_by_nrecno(c, &id->nrecno, &name) < 0) + goto finish; + + if (write_entry(target, &name, &id->md, meta) < 0) + goto finish; + } + + if (ret != DB_NOTFOUND) { + c->db_version_timestamp->err(c->db_id_meta, ret, "id_meta::c_get"); + goto finish; + } + + if (args.verbose_flag) + fprintf(stderr, "Removed %u of %u file entries.\n", t-n, t); + + r = 0; + +finish: + if (cursor) + cursor->c_close(cursor); + + return r; +} + + +static int copy_history(struct syrep_db_context *c, struct syrep_db_context *target, uint32_t limit) { + int ret, r = -1; + DBT key, data; + DBC *cursor = NULL; + unsigned n = 0, t = 0; + assert(c); + + if ((ret = c->db_version_timestamp->cursor(c->db_version_timestamp, NULL, &cursor, 0)) != 0) { + c->db_version_timestamp->err(c->db_version_timestamp, ret, "version_timestamp"); + goto finish; + } + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + while ((ret = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0) { + struct syrep_timestamp *timestamp = (struct syrep_timestamp*) data.data; + assert(timestamp); + + if (interrupted) { + fprintf(stderr, "Canceled.\n"); + goto finish; + } + + rotdash(); + t++; + + if (timestamp->t < limit) + continue; + + n++; + + /* copy it */ + + if ((ret = target->db_version_timestamp->put(target->db_version_timestamp, NULL, &key, &data, 0)) != 0) { + c->db_version_timestamp->err(c->db_version_timestamp, ret, "version_timestamp::put"); + goto finish; + } + + + } + + if (ret != DB_NOTFOUND) { + c->db_version_timestamp->err(c->db_version_timestamp, ret, "version_timestamp::c_get"); + goto finish; + } + + if (args.verbose_flag) + fprintf(stderr, "Removed %u of %u history entries.\n", t-n, t); + + r = 0; + +finish: + if (cursor) + cursor->c_close(cursor); + + return r; +} + +int forget(struct syrep_db_context *c, struct syrep_db_context *target) { + uint32_t t; + time_t now, limit; + + assert(c && target); + + if (args.remember_arg < 0) { + fprintf(stderr, "ERROR: The remembrance time has to be greater or equal to 0\n"); + return -1; + } + + t = args.remember_arg*24*60*60; + time(&now); + limit = t > now ? 0 : now-t; + + if (args.verbose_flag) { + fprintf(stderr, "Current time is %s", ctime(&now)); + fprintf(stderr, "Forgetting all entries prior to %s", ctime(&limit)); + } + + if (copy_entries(c, target, (uint32_t) limit) < 0) + return -1; + + if (copy_history(c, target, (uint32_t) limit) < 0) + return -1; + + target->timestamp = c->timestamp; + target->version = c->version; + free(target->origin); + target->origin = strdup(c->origin); + + target->modified = 1; + + return 0; +} diff --git a/src/forget.h b/src/forget.h new file mode 100644 index 0000000..c9716b2 --- /dev/null +++ b/src/forget.h @@ -0,0 +1,28 @@ +#ifndef fooforgethfoo +#define fooforgethfoo + +/* $Id$ */ + +/*** + This file is part of syrep. + + syrep is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + syrep is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with syrep; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +***/ + +#include "context.h" + +int forget(struct syrep_db_context *c, struct syrep_db_context *target); + +#endif diff --git a/src/history.c b/src/history.c index ff8532e..7c6a8a2 100644 --- a/src/history.c +++ b/src/history.c @@ -53,7 +53,7 @@ int history(struct syrep_db_context *c) { assert(version && timestamp); - fprintf(stderr, "%4u %10u %s", version->v, timestamp->t, ctime((time_t*) (×tamp->t))); + printf("%4u %10u %s", version->v, timestamp->t, ctime((time_t*) (×tamp->t))); } if (ret != DB_NOTFOUND) { diff --git a/src/package.c b/src/package.c index c2841ad..ef37c35 100644 --- a/src/package.c +++ b/src/package.c @@ -549,8 +549,6 @@ struct package* package_open(const char *fn, int force) { } if (fn) { - - if (!strcmp(fn, "-")) p->read_fd = STDIN_FILENO; else if ((p->read_fd = open(fn, O_RDONLY)) < 0) { diff --git a/src/syrep.c b/src/syrep.c index 266082f..5ac60bd 100644 --- a/src/syrep.c +++ b/src/syrep.c @@ -56,6 +56,7 @@ #include "extract.h" #include "makepatch.h" #include "cleanup.h" +#include "forget.h" #include "svn-revision.h" @@ -293,7 +294,6 @@ static int do_foreach(int (*func) (struct syrep_db_context *c), int m) { } } - if (func(c) < 0) goto finish; @@ -304,7 +304,6 @@ static int do_foreach(int (*func) (struct syrep_db_context *c), int m) { } } - if (args.inputs_num > 1 && i < args.inputs_num-1) fprintf(stderr, "\n"); @@ -452,7 +451,67 @@ static int do_cleanup(void) { finish: return r; +} + +static int do_forget(void) { + char *path = NULL; + int r = 1, i; + struct syrep_db_context *c = NULL, *target = NULL; + + if (args.inputs_num < 1) + fprintf(stderr, "WARNING: No repository or snapshot to specified!\n"); + for (i = 0; i < args.inputs_num; i++) { + if (args.local_temp_flag && isdirectory(args.inputs[i]) >= 1) { + const char *p = get_attached_filename(args.inputs[i], SYREP_TEMPDIR); + mkdir(p, 0777); + setenv("TMPDIR", p, 1); + } + + if (!(path = strdup(get_snapshot_filename(args.inputs[i], SYREP_SNAPSHOTFILENAME)))) + goto finish; + + if (!(c = db_context_open(path, 0))) + goto finish; + + if (!(target = db_context_open(NULL, 1))) + goto finish; + + if (args.inputs_num > 1) + fprintf(stderr, "*** %s ***\n", path); + + if (forget(c, target) < 0) + goto finish; + + if (args.inputs_num > 1 && i < args.inputs_num-1) + fprintf(stderr, "\n"); + + db_context_free(c); + + if (db_context_save(target, path) < 0) + goto finish; + + db_context_free(target); + c = NULL; + target = NULL; + + free(path); + path = NULL; + } + + r = 0; + +finish: + if (c) + db_context_free(c); + + if (target) + db_context_free(target); + + if (path) + free(path); + + return r; } static void sigint(int s) { @@ -477,58 +536,66 @@ static int help(const char *argv0) { "Usage: %s [options...] [arguments...]\n\n" "General options:\n" - " -v --verbose Enable verbose operation\n" - " -T --local-temp Use temporary directory inside repository\n" - " --ignore-origin Don't warn if snapshot not local in update, merge, makepatch\n" - " -z --compress Compress snapshots or patches\n" - " -p --progress Show progress\n\n" + " -v --verbose Enable verbose operation\n" + " -T --local-temp Use temporary directory inside repository\n" + " --ignore-origin Don't warn if snapshot not local in update, merge, makepatch\n" + " -z --compress Compress snapshots or patches\n" + " -p --progress Show progress\n\n" "General commands:\n" - " -h --help Print help and exit\n" - " -V --version Print version and exit\n\n" + " -h --help Print help and exit\n" + " -V --version Print version and exit\n\n" "Specific commands:\n" - " --list SNAPSHOT List a repository snapshot\n" - " --show-deleted Show deleted entries of repository snapshot\n" - " --show-by-md Show files by message digests\n" - " --show-times Show first and last seen times\n" - " --sort Sort chronologically\n\n" + " --list SNAPSHOT List a repository snapshot\n" + " --show-deleted Show deleted entries of repository snapshot\n" + " --show-by-md Show files by message digests\n" + " --show-times Show first and last seen times\n" + " --sort Sort chronologically\n\n" - " --info SNAPSHOT Show information about a repository or snapshot\n\n" + " --info SNAPSHOT Show information about a repository or snapshot\n\n" - " --history SNAPSHOT Show history of a repository or snapshot\n\n" + " --history SNAPSHOT Show history of a repository or snapshot\n\n" - " --dump SNAPSHOT Show a structure dump of a repository or snapshot\n\n" + " --dump SNAPSHOT Show a structure dump of a repository or snapshot\n\n" - " --update DIRECTORY Update (or create) a repository snapshot\n" - " -SSTRING --snapshot=STRING Use the specified snapshot file instead of the one contained in the repository\n" - " -CSTRING --cache=STRING Use the specified cache file instead of the one contained in the repository\n" - " --no-cache Don't use a message digest cache\n" - " --no-purge Don't purge obsolete entries from cache after update run\n" - " --ro-cache Use read only cache\n\n" + " --update DIRECTORY Update (or create) a repository snapshot\n" + " -SSTRING --snapshot=STRING Use a different snapshot file than the one contained\n" + " in the repository\n" + " -CSTRING --cache=STRING Use a different cache file than the one contained in\n" + " the repository\n" + " --no-cache Don't use a message digest cache\n" + " --no-purge Don't purge obsolete entries from cache after update run\n" + " --ro-cache Use read only cache\n\n" - " --diff SNAPSHOT SNAPSHOT Show difference between two repositories or snapshots\n\n" + " --diff SNAPSHOT SNAPSHOT Show difference between two repositories or snapshots\n" + " --sizes -s Show sizes for files to copy (works only with repositories)\n" + " --human-readable -H Show sizes in human readable from\n" - " --merge SNAPSHOT DIRECTORY Merge a snapshot into a repository (perform deletes, renames only)\n" - " --merge PATCH DIRECTORY Merge a patch into a repository\n" - " --merge DIRECTORY DIRECTORY Merge a repository into a repository\n" - " -q --question Ask a question before each action\n" - " -P --prune-empty Prune empty directories\n" - " --keep-trash Don't empty trash\n" - " --check-md Check message digest of files prior to deletion or replacement\n" - " --always-copy Always copy instead of hard link\n\n" + " --merge SNAPSHOT DIRECTORY Merge a snapshot into a repository (perform deletes,\n" + " renames only)\n" + " --merge PATCH DIRECTORY Merge a patch into a repository\n" + " --merge DIRECTORY DIRECTORY Merge a repository into a repository\n" + " -q --question Ask a question before each action\n" + " -P --prune-empty Prune empty directories\n" + " --keep-trash Don't empty trash\n" + " --check-md Check message digest of files prior to deletion or replacement\n" + " --always-copy Always copy instead of hard link\n\n" - " --makepatch DIRECTORY SNAPSHOT Make a patch against the specified repository\n" - " -oSTRING --output-file=STRING Write output to specified file instead of STDOUT\n" - " --include-all Include files in patch which do exist on the other side under a different name\n\n" + " --makepatch DIRECTORY SNAPSHOT Make a patch against the specified repository\n" + " -oSTRING --output-file=STRING Write output to specified file instead of STDOUT\n" + " --include-all Include files in patch which do exist on the other side under a \n" + " different name\n\n" - " --extract SNAPSHOT Extract the contents of a snapshot or patch\n" - " -DSTRING --output-directory=STRING Write output to specified directory\n\n" + " --extract SNAPSHOT Extract the contents of a snapshot or patch\n" + " -DSTRING --output-directory=STRING Write output to specified directory\n\n" - " --cleanup DIRECTORY Remove syrep info from repository\n" - " -lINT --cleanup-level=INT 1 - just remove temporary data and trash (default)\n" - " 2 - remove MD cache as well\n" - " 3 - remove all syrep data\n", + " --cleanup DIRECTORY Remove syrep info from repository\n" + " -lINT --cleanup-level=INT 1 - just remove temporary data and trash (default)\n" + " 2 - remove MD cache as well\n" + " 3 - remove all syrep data\n\n" + " --forget SNAPSHOT Repackage snapshot dropping outdated information\n" + " --remember DAYS Information of how many days should be kept? (defaults to 180)\n", argv0, argv0); return 0; @@ -599,6 +666,8 @@ int main(int argc, char *argv[]) { return do_makepatch(); else if (args.cleanup_flag) return do_cleanup(); + else if (args.forget_flag) + return do_forget(); help(bn); diff --git a/src/syrep.ggo b/src/syrep.ggo index d2a7bb1..53c60ae 100644 --- a/src/syrep.ggo +++ b/src/syrep.ggo @@ -62,3 +62,6 @@ option "extract" - "Extract the context of a snapshot or patch" flag off option "cleanup" - "Remove syrep info from repository" flag off option "cleanup-level" l "cleanup: 1 - just remove temporary data and trash (default); 2 - remove MD cache as well; 3 - remove all syrep data" int default="1" no + +option "forget" - "Forget old snapshot entries" flag off + option "remember" R "forget: information of how many days to remeber" int default="180" no diff --git a/src/update.c b/src/update.c index 6fc2d06..4fe6758 100644 --- a/src/update.c +++ b/src/update.c @@ -59,7 +59,7 @@ static int dbput(DB* db, const void *k, int klen, const void*d, int dlen, int f) 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) { +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; struct syrep_nrecno nrecno; int f; @@ -95,7 +95,7 @@ static int write_entry(struct syrep_db_context *c, const struct syrep_name *name if ((f = dbput(c->db_nrecno_lastmd, &nrecno, sizeof(struct syrep_nrecno), md, sizeof(struct syrep_md), 0)) < 0) return -1; - //fprintf(stderr, "Insert: %s %i\n", name->path, f); + /*fprintf(stderr, "Insert: %s %i\n", name->path, f);*/ c->modified = 1; return 0; diff --git a/src/update.h b/src/update.h index 81e26d0..57040f5 100644 --- a/src/update.h +++ b/src/update.h @@ -23,7 +23,11 @@ #include "context.h" #include "cache.h" +#include "dbstruct.h" int update(struct syrep_db_context *c, struct syrep_md_cache *cache); +/* This is exported solely for usage in forget.c */ +int write_entry(struct syrep_db_context *c, const struct syrep_name *name, const struct syrep_md *md, const struct syrep_meta *meta); + #endif -- cgit