ref: d8bde8f7b35078dd07ee76bc493031aac315fcbb
parent: 45cc898e4a626cc67312629ae6fe2d25e6cfd733
author: cinap_lenrek <cinap_lenrek@centraldogma>
date: Tue Oct 25 10:09:41 EDT 2011
torrent: fix \0 escaping bug, add -c option to create new torrents
--- a/sys/man/1/torrent
+++ b/sys/man/1/torrent
@@ -5,21 +5,21 @@
.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 @@
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 @@
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
--- a/sys/src/cmd/ip/torrent.c
+++ b/sys/src/cmd/ip/torrent.c
@@ -46,9 +46,10 @@
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 @@
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)
@@ -745,6 +746,55 @@
}
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)
{
char *p;
@@ -800,7 +850,7 @@
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");
}
@@ -807,18 +857,22 @@
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 @@
case 'v':
vflag = 1;
break;
+ case 'c':
+ cflag = 1;
+ break;
case 'd':
debug++;
break;
@@ -838,7 +895,14 @@
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 @@
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')