torrent: fix \0 escaping bug, add -c option to create new torrents

front
cinap_lenrek 2011-10-25 14:09:41 +02:00
parent 45cc898e4a
commit d8bde8f7b3
2 changed files with 107 additions and 19 deletions

View File

@ -5,21 +5,21 @@ torrent \- bittorrent client
.B ip/torrent
[
.B -d
]
[
] [
.B -v
]
[
] [
.B -p
]
[
] [
.B -m
.I mtpt
]
[
] [
.B -t
.I url
] [
.B -s
]
[
] [
.B -c
] [
.I file
]
.SH DESCRIPTION
@ -36,7 +36,24 @@ Before files can be transmitted, a torrent-file needs
to be created describing the pieces of the files and
other meta-data like network addresses of the trackers.
.PP
.I Torrent
This is done with the
.B -c
option. If provided,
.I torrent
reads the file given at the final
.I file
argument (or standard-input when omited) and writes
a torrent file to standard-output and exits.
A tracker
.I url
should be given with the
.B -t
option in that case.
.PP
Without the
.B -c
option,
.I torrent
downloads the files that are described in the torrent-file
given by the
.I file
@ -74,7 +91,13 @@ To monitor the download progress, the
option can be given to cause the completed and total number of
pieces written as a line of text to standard-output in one
second intervals.
.SH EXAMPLE
.SH EXAMPLES
Create new torrent file
.EX
ip/torrent -t http://exodus.desync.com/announce \\
-c 9atom.iso >9atom.torrent
.EE
.LP
Download the latest iso file of the distribution
.EX
cd /tmp

View File

@ -46,9 +46,10 @@ enum {
MAXIO = 16*1024,
};
int debug, sflag, pflag, vflag;
int debug;
int killgroup = -1;
int port = 6881;
char *deftrack = "http://exodus.desync.com/announce";
char *mntweb = "/mnt/web";
uchar infohash[20];
uchar peerid[20];
@ -736,7 +737,7 @@ Hfmt(Fmt *f)
else
e = s + strlen((char*)s);
for(; s < e; s++)
if(fmtprint(f, ((*s >= '0' && *s <= '9') ||
if(fmtprint(f, *s && ((*s >= '0' && *s <= '9') ||
(*s >= 'a' && *s <= 'z') ||
(*s >= 'A' && *s <= 'Z') ||
strchr(".-_~", *s)) ? "%c" : "%%%.2x", *s) < 0)
@ -744,6 +745,55 @@ Hfmt(Fmt *f)
return 0;
}
int
mktorrent(int fd, char *url)
{
uchar *b, h[20];
Dir *d;
int n;
if((d = dirfstat(fd)) == nil)
return -1;
if(d->qid.type == QTDIR){
free(d);
werrstr("file is a directory");
return -1;
}
if(d->length == 0){
free(d);
werrstr("empty file");
return -1;
}
blocksize = 1024*1024;
npieces = (d->length + blocksize-1) / blocksize;
print("d");
print("8:announce%ld:%s", strlen(url), url);
print("4:info");
print("d");
print("4:name%ld:%s", strlen(d->name), d->name);
print("6:lengthi%llde", d->length);
print("12:piece lengthi%de", blocksize);
print("6:pieces%d:", npieces*sizeof(h));
free(d);
b = malloc(blocksize);
while((n = readn(fd, b, blocksize)) > 0){
sha1(b, n, h, nil);
if(write(1, h, sizeof(h)) != sizeof(h)){
free(b);
return -1;
}
npieces--;
}
free(b);
if(npieces){
werrstr("read failed: %r");
return -1;
}
print("e");
print("e");
return 0;
}
int
mkdirs(char *s)
{
@ -800,25 +850,29 @@ killnote(void *, char *)
void
usage(void)
{
fprint(2, "usage: %s [ -vsdp ] [ -m mtpt ] [ torrentfile ]\n", argv0);
fprint(2, "usage: %s [ -vsdpc ] [ -m mtpt ] [ -t url ] [ file ]\n", argv0);
exits("usage");
}
void
main(int argc, char *argv[])
{
int sflag, pflag, vflag, cflag, fd, i, n;
Dict *info, *torrent, *d;
char *p, *s, *e, *url;
File **fp, *f;
char *p, *s, *e;
int fd, i, n;
vlong len;
fmtinstall('H', Hfmt);
url = nil;
sflag = pflag = vflag = cflag = 0;
ARGBEGIN {
case 'm':
mntweb = EARGF(usage());
break;
case 't':
url = EARGF(usage());
break;
case 's':
sflag = 1;
break;
@ -828,6 +882,9 @@ main(int argc, char *argv[])
case 'v':
vflag = 1;
break;
case 'c':
cflag = 1;
break;
case 'd':
debug++;
break;
@ -838,7 +895,14 @@ main(int argc, char *argv[])
fd = 0;
if(*argv)
if((fd = open(*argv, OREAD)) < 0)
sysfatal("open torrent: %r");
sysfatal("open: %r");
if(cflag){
if(url == nil)
url = deftrack;
if(mktorrent(fd, url) < 0)
sysfatal("%r");
exits(0);
}
if((n = readall(fd, &p)) <= 0)
sysfatal("read torrent: %r");
bparse(p, p+n, &torrent);
@ -925,6 +989,7 @@ main(int argc, char *argv[])
for(i=8; i<sizeof(peerid); i++)
peerid[i] = nrand(10)+'0';
server();
tracker(url);
tracker(dstr(dlook(torrent, "announce")));
for(d = dlook(torrent, "announce-list"); d && d->typ == 'l'; d = d->next)
if(d->val && d->val->typ == 'l')