summaryrefslogtreecommitdiff
path: root/files.c
diff options
context:
space:
mode:
Diffstat (limited to 'files.c')
-rw-r--r--files.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/files.c b/files.c
new file mode 100644
index 0000000..4fb6d49
--- /dev/null
+++ b/files.c
@@ -0,0 +1,271 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2005 Dimitri Sokolyuk <demon@vhost.dyndns.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <openssl/sha.h>
+
+#include <sys/param.h> /* bitfield */
+#include <sys/queue.h>
+#include <sys/types.h> /* mkdir() */
+#include <sys/stat.h>
+
+#include <err.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "meta.h"
+#include "files.h"
+#include "tools.h"
+
+#ifndef lint
+static const char rcsid[] = "@(#)$Id$";
+#endif /* not lint */
+
+/*
+ * 0 1 2 3 4 5 6 7
+ * pieces +---+---+---+---+---+---+---+-+
+ * files +--------+-------+-+----------+
+ * 0 1 2 3
+ */
+
+/* TODO: rewrite btread() and btwrite() so, that
+ * only required files are open (pending, DONE)
+ * on the one hand it makes more overhead on opening files, on the other
+ * hand we need only one file descriptor and we have no limitations on number of files
+ * so more descriptors remains for the network communication by the same rlimit value
+ */
+
+#define FMODE "a+"
+
+int
+btwrite(struct btmeta *mp, char *piece, off_t len, int npiece)
+{
+ FILE *fd;
+ struct btfile *fp;
+ off_t off, eof, left;
+
+ fp = SIMPLEQ_FIRST(&mp->flist);
+ /* TODO: check piece first */
+ off = mp->plength * npiece;
+ eof = fp->length;
+
+ /* find right file */
+ while (off > eof) {
+ off -= fp->length;
+ fp = SIMPLEQ_NEXT(fp, link);
+ eof = fp->length;
+ }
+ if (fp == NULL)
+ return -1; /* XXX */
+
+ left = len;
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, off, SEEK_SET);
+ if ((off + len) <= eof) {
+ left -= fwrite(piece, sizeof(char), len, fd);
+ } else {
+ left -= fwrite(piece, sizeof(char), eof - off, fd);
+ fclose(fd);
+ fp = SIMPLEQ_NEXT(fp, link);
+
+ for (; left > fp->length; fp = SIMPLEQ_NEXT(fp, link)) {
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, 0L, SEEK_SET);
+ left -= fwrite(piece + len - left, sizeof(char),
+ fp->length, fd);
+ fclose(fd);
+ }
+
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, 0L, SEEK_SET);
+ left -= fwrite(piece + len - left, sizeof(char), left, fd);
+ }
+ fclose(fd);
+
+ return ((len - left) == 0);
+}
+
+int
+btread(struct btmeta *mp, char *piece, off_t len, int npiece)
+{
+ FILE *fd;
+ struct btfile *fp;
+ off_t off, eof, left, ret;
+
+ fp = SIMPLEQ_FIRST(&mp->flist);
+ off = mp->plength * npiece;
+ eof = fp->length;
+
+ /* find right file */
+ while (off > eof) {
+ off -= fp->length;
+ fp = SIMPLEQ_NEXT(fp, link);
+ eof = fp->length;
+ }
+
+ left = len;
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, off, SEEK_SET);
+ if ((off + len) <= eof) {
+ ret = fread(piece, sizeof(char), len, fd);
+ left -= (ret > 0) ? ret : len;
+ } else {
+ ret = fread(piece, sizeof(char), eof - off, fd);
+ left -= (ret > 0) ? ret : eof - off;
+ fclose(fd);
+ fp = SIMPLEQ_NEXT(fp, link);
+
+ for (; left > fp->length; fp = SIMPLEQ_NEXT(fp, link)) {
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, 0L, SEEK_SET);
+ ret = fread(piece + len - left, sizeof(char),
+ fp->length, fd);
+ left -= (ret > 0) ? ret : fp->length;
+ fclose(fd);
+ }
+
+ fd = fopen(fp->path, FMODE);
+ fseek(fd, 0L, SEEK_SET);
+ ret = fread(piece + len - left, sizeof(char), left, fd);
+ left -= (ret > 0) ? ret : left;
+ }
+ fclose(fd);
+
+ return (ret > 0);
+}
+
+off_t
+btsizeofpiece(struct btmeta *mp, int n)
+{
+ return (n == mp->npieces - 1) ? mp->size % mp->plength : mp->plength;
+}
+
+int
+btmkhier(struct btmeta *mp)
+{
+ struct btfile *fp;
+ struct stat st;
+ char path[MAXPATHLEN], *p;
+
+ if (mp->nfiles > 1) {
+ SIMPLEQ_FOREACH(fp, &mp->flist, link) {
+ strlcpy(path, fp->path, sizeof(path));
+ p = path;
+ while ((p = strchr(p, '/')) != NULL) {
+ /* TODO: add proper checking */
+ *p = '\0';
+ if (stat(path, &st) == -1)
+ mkdir(path, 0755);
+ else if (!(st.st_mode & S_IFDIR)) {
+ fprintf(stderr, "remove %s\n", path);
+ return -1;
+ }
+ *p++ = '/';
+ }
+ }
+ }
+
+ return 0;
+}
+
+int
+btcheck(u_char *key, char *src, off_t len)
+{
+ u_char sha[SHA1LEN];
+
+ /* FIXME: it's so ugly */
+ SHA1((u_char *) src, len, sha);
+ return (strncmp((char *) key, (char *) sha, SHA1LEN) == 0);
+}
+
+void
+#if 0
+btchkfiles(struct btmeta *mp, void (*progress)(struct btmeta *, int))
+#else
+btchkfiles(struct btmeta *mp, struct progresscb *cb)
+#endif
+{
+ char *buf;
+ off_t len;
+ int n;
+
+ if ((buf = calloc(mp->plength, sizeof(char))) == NULL)
+ return;
+
+ mp->left = mp->size;
+
+ for (n = 0, mp->good = 0; n < mp->npieces; n++) {
+ len = btsizeofpiece(mp, n);
+ if (btread(mp, buf, len, n)) {
+ if (btcheck(mp->pieces[n], buf, len)) {
+ btsetbit(mp->bitfield, n);
+ mp->good++;
+ mp->left -= len;
+ }
+ }
+#if 0
+ if (progress != NULL)
+ (*progress)(mp, n + 1);
+ }
+ if (progress != NULL)
+ (*progress)(mp, n + 1);
+#else
+ if (cb && cb->progress)
+ (*cb->progress)(mp, n + 1);
+ }
+ if (cb && cb->done)
+ (*cb->done)(mp);
+#endif
+
+ free(buf);
+}
+
+/* XXX */
+int
+btchkwrite(struct btmeta *mp, char *buf, int n)
+{
+ off_t len;
+
+ len = btsizeofpiece(mp, n);
+
+ if (btcheck(mp->pieces[n], buf, len)) {
+ if (btwrite(mp, buf, len, n)) {
+ btsetbit(mp->bitfield, n);
+ mp->left -= len;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/* fallback progress indicator */
+
+void
+btchkprogress(struct btmeta *mp, int n)
+{
+ printf("\r%s: checking %d of %d (%d ok)", mp->fname,
+ n, mp->npieces, mp->good);
+ fflush(stdout);
+}
+
+void
+btchkdone(struct btmeta *mp)
+{
+ printf("\r%s: total good pieces %d/%d (%d%%)\n", mp->fname,
+ mp->good, mp->npieces, mp->good * 100 / mp->npieces);
+}