From 51b913eb2ff91adfe8cd5e417759a6057c5a8a21 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 13 Nov 2008 16:17:55 +0000 Subject: XBitTorrent --- files.c | 271 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 files.c (limited to 'files.c') 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 + * + * 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 + +#include /* bitfield */ +#include +#include /* mkdir() */ +#include + +#include + +#include +#include +#include + +#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); +} -- cgit v1.2.3