summaryrefslogtreecommitdiffstats
path: root/sizes.c
diff options
context:
space:
mode:
Diffstat (limited to 'sizes.c')
-rw-r--r--sizes.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/sizes.c b/sizes.c
new file mode 100644
index 0000000..b10ccab
--- /dev/null
+++ b/sizes.c
@@ -0,0 +1,256 @@
+/* This file is part of "reprepro"
+ * Copyright (C) 2011 Bernhard R. Link
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program 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 this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02111-1301 USA
+ */
+#include <config.h>
+
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "error.h"
+#include "strlist.h"
+#include "distribution.h"
+#include "database.h"
+#include "database_p.h"
+#include "files.h"
+#include "sizes.h"
+
+struct distribution_sizes {
+ struct distribution_sizes *next;
+ const char *codename;
+ char *v;
+ size_t codename_len;
+ struct {
+ unsigned long long all, onlyhere;
+ } this, withsnapshots;
+ bool seen, seensnapshot;
+};
+
+static void distribution_sizes_freelist(struct distribution_sizes *ds) {
+ while (ds != NULL) {
+ struct distribution_sizes *s = ds;
+ ds = ds->next;
+
+ free(s->v);
+ free(s);
+ }
+}
+
+static bool fromdist(struct distribution_sizes *dist, const char *data, size_t len, bool *snapshot_p) {
+ if (len < dist->codename_len + 1)
+ return false;
+ if (data[dist->codename_len] == '=')
+ *snapshot_p = true;
+ else if (data[dist->codename_len] == '|' ||
+ data[dist->codename_len] == ' ')
+ *snapshot_p = false;
+ else
+ return false;
+ return memcmp(data, dist->codename, dist->codename_len) == 0;
+}
+
+static retvalue count_sizes(struct cursor *cursor, bool specific, struct distribution_sizes *ds, unsigned long long *all_p, unsigned long long *onlyall_p) {
+ const char *key, *data;
+ size_t len;
+ char *last_file = NULL;
+ unsigned long long filesize = 0;
+ bool onlyone = true;
+ struct distribution_sizes *last_dist;
+ struct distribution_sizes *s;
+ bool snapshot;
+ unsigned long long all = 0, onlyall = 0;
+
+ while (cursor_nexttempdata(rdb_references, cursor,
+ &key, &data, &len)) {
+ if (last_file == NULL || strcmp(last_file, key) != 0) {
+ if (last_file != NULL) {
+ free(last_file);
+ for (s = ds ; s != NULL ; s = s->next) {
+ s->seen = false;
+ s->seensnapshot = false;
+ }
+ }
+ last_file = strdup(key);
+ if (FAILEDTOALLOC(last_file))
+ return RET_ERROR_OOM;
+ onlyone = true;
+ filesize = 0;
+ last_dist = NULL;
+ }
+ if (data[0] == 'u' && data[1] == '|') {
+ data += 2;
+ len -= 2;
+ } else if (data[0] == 's' && data[1] == '=') {
+ data += 2;
+ len -= 2;
+ }
+ if (last_dist != NULL &&
+ fromdist(last_dist, data, len, &snapshot)) {
+ /* same distribution again */
+ if (!snapshot && !last_dist->seen) {
+ last_dist->seen = true;
+ last_dist->this.all += filesize;
+ if (onlyone)
+ last_dist->this.onlyhere += filesize;
+ }
+ continue;
+ }
+ s = ds;
+ while (s != NULL && !fromdist(s, data, len, &snapshot))
+ s = s->next;
+ if (s == NULL) {
+ if (onlyone && last_dist != NULL) {
+ if (!last_dist->seen)
+ last_dist->this.onlyhere -= filesize;
+ last_dist->withsnapshots.onlyhere -= filesize;
+ }
+ if (last_dist != NULL)
+ onlyall -= filesize;
+ onlyone = false;
+ if (!specific) {
+ struct distribution_sizes **s_p = &ds->next;
+ const char *p;
+
+ p = data;
+ while (*p != '\0' && *p != ' ' && *p != '|'
+ && *p != '=')
+ p++;
+ if (*p == '\0')
+ continue;
+ while (*s_p != NULL)
+ s_p = &(*s_p)->next;
+ s = zNEW(struct distribution_sizes);
+ if (FAILEDTOALLOC(s)) {
+ free(last_file);
+ return RET_ERROR_OOM;
+ }
+ *s_p = s;
+ s->v = strndup(data, (p-data) + 1);
+ if (FAILEDTOALLOC(s)) {
+ free(last_file);
+ return RET_ERROR_OOM;
+ }
+ s->v[p-data] = '*';
+ s->codename = s->v;
+ s->codename_len = p-data;
+ snapshot = *p == '=';
+ } else
+ /* last_dist not changed on purpose */
+ continue;
+ }
+ /* found it to belong to distribution s */
+ if (s->seen) {
+ assert (last_dist != NULL);
+ assert (!onlyone);
+ continue;
+ }
+ if (s->seensnapshot && !snapshot) {
+ s->seen = true;
+ s->this.all += filesize;
+ assert (last_dist != NULL);
+ assert (!onlyone);
+ continue;
+ }
+ /* distribution seen for this file the first time */
+ if (last_dist != NULL) {
+ if (onlyone) {
+ last_dist->withsnapshots.onlyhere -= filesize;
+ if (last_dist->seen)
+ last_dist->this.onlyhere -= filesize;
+ onlyone = false;
+ }
+ assert (filesize != 0);
+ } else {
+ /* and this is the first time
+ * we are interested in the file */
+ filesize = files_getsize(key);
+ assert (filesize != 0);
+ if (onlyone)
+ onlyall += filesize;
+ all += filesize;
+ }
+ last_dist = s;
+ if (snapshot) {
+ s->seensnapshot = true;
+ } else {
+ s->seen = true;
+ last_dist->this.all += filesize;
+ if (onlyone)
+ last_dist->this.onlyhere += filesize;
+ }
+ last_dist->withsnapshots.all += filesize;
+ if (onlyone)
+ last_dist->withsnapshots.onlyhere += filesize;
+ }
+ free(last_file);
+ *all_p = all;
+ *onlyall_p = onlyall;
+ return RET_OK;
+}
+
+retvalue sizes_distributions(struct distribution *alldistributions, bool specific) {
+ struct cursor *cursor;
+ retvalue result, r;
+ struct distribution_sizes *ds = NULL, **lds = &ds, *s;
+ struct distribution *d;
+ unsigned long long all = 0, onlyall = 0;
+
+ for (d = alldistributions ; d != NULL ; d = d->next) {
+ if (!d->selected)
+ continue;
+ s = zNEW(struct distribution_sizes);
+ if (FAILEDTOALLOC(s)) {
+ distribution_sizes_freelist(ds);
+ return RET_ERROR_OOM;
+ }
+ s->codename = d->codename;
+ s->codename_len = strlen(d->codename);
+ *lds = s;
+ lds = &s->next;
+ }
+ if (ds == NULL)
+ return RET_NOTHING;
+ r = table_newglobalcursor(rdb_references, true, &cursor);
+ if (!RET_IS_OK(r)) {
+ distribution_sizes_freelist(ds);
+ return r;
+ }
+ result = count_sizes(cursor, specific, ds, &all, &onlyall);
+ r = cursor_close(rdb_references, cursor);
+ RET_ENDUPDATE(result, r);
+ if (RET_IS_OK(result)) {
+ printf("%-15s %13s %13s %13s %13s\n",
+ "Codename", "Size", "Only", "Size(+s)",
+ "Only(+s)");
+ for (s = ds ; s != NULL ; s = s->next) {
+ printf("%-15s %13llu %13llu %13llu %13llu\n",
+ s->codename,
+ s->this.all,
+ s->this.onlyhere,
+ s->withsnapshots.all,
+ s->withsnapshots.onlyhere);
+ }
+ if (specific && ds->next != NULL)
+ printf("%-15s %13s %13s %13llu %13llu\n",
+ "<all selected> ",
+ "", "",
+ all, onlyall);
+ }
+ distribution_sizes_freelist(ds);
+ return result;
+}